﻿namespace MailChimp.Types

open System
open System.Xml
open System.Xml.Serialization
open System.Runtime.Serialization

//------------------------------------------------------------------------------
//  (*) Errors
//------------------------------------------------------------------------------

[<DataContract(Namespace = "")>]
type MCError() =
    inherit Error()
    [<field: DataMember(Name = "code", IsRequired = true)>]
    let code: int = 0
    [<field: DataMember(Name = "error", IsRequired = true)>]
    let msg: string = null

    override x.Code = code
    override x.Message = msg

[<DataContract(Namespace = "")>]
type EmailError =
  { [<field: DataMember(Name = "email_address")>]
    Email: string;
    [<field: DataMember(Name = "error")>]
    Error: string }

[<DataContract(Namespace = "")>]
type internal EmailErrors =
    { [<field: DataMember(Name = "data")>]
      Errors: MCList<EmailError> }

module IH = InputHelper

//==================================================================================
//  Security related section
//==================================================================================

module Security =

    [<DataContract(Namespace = "")>]
    type ApiKey =
      { [<field: DataMember(Name = "apikey")>]
        Key: string;
        [<field: DataMember(Name = "created_at")>]
        Created: MCDateTime;
        [<field: DataMember(Name = "expired_at")>]
        Expired: MCDateTime }

//==================================================================================
//  List related section
//==================================================================================

module List =

    //------------------------------------------------------------------------------
    //  (*) Lists
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type SortField =
        | [<EnumMember(Value = "created")>] Created = 0
        | [<EnumMember(Value = "web")>] Web = 1

    [<DataContract(Namespace = "")>]
    type Filter() =
        [<DefaultValue; field: DataMember(Name = "list_id")>]
        val mutable ListID: string mcseq
        [<DefaultValue; field: DataMember(Name = "list_name")>]
        val mutable ListName: string
        [<DefaultValue; field: DataMember(Name = "from_name")>]
        val mutable FromName: string
        [<DefaultValue; field: DataMember(Name = "from_email")>]
        val mutable FromEmail: string
        [<DefaultValue; field: DataMember(Name = "from_subject")>]
        val mutable FromSubject: string
        [<DefaultValue; field: DataMember(Name = "created_before")>]
        val mutable CreatedBefore: DateTime opt
        [<DefaultValue; field: DataMember(Name = "created_after")>]
        val mutable CreatedAfter: DateTime opt
        [<DefaultValue; field: DataMember(Name = "exact")>]
        val mutable Exact: bool opt

        interface IInput with
            member x.ToInput() = IH.build x

    [<DataContract(Namespace = "")>]
    type Stats =
      { [<field: DataMember(Name = "member_count")>]
        MemberCount: int;
        [<field: DataMember(Name = "unsubscribe_count")>]
        UnsubscribeCount: int;
        [<field: DataMember(Name = "cleaned_count")>]
        CleanedCount: int;
        [<field: DataMember(Name = "member_count_since_send")>]
        MemberCountSinceSend: int;
        [<field: DataMember(Name = "unsubscribe_count_since_send")>]
        UnsubscribeCountSinceSend: int;
        [<field: DataMember(Name = "cleaned_count_since_send")>]
        CleanedCountSinceSend: int;
        [<field: DataMember(Name = "campaign_count")>]
        CampaignCount: int;
        [<field: DataMember(Name = "grouping_count")>]
        GroupingCount: int;
        [<field: DataMember(Name = "group_count")>]
        GroupCount: int;
        [<field: DataMember(Name = "merge_var_count")>]
        MergeVarCount: int;
        [<field: DataMember(Name = "avg_sub_rate")>]
        AvgSubRate: float mcnull;
        [<field: DataMember(Name = "avg_unsub_rate")>]
        AvgUnsubRate: float mcnull;
        [<field: DataMember(Name = "target_sub_rate")>]
        TargetSubRate: float mcnull;
        [<field: DataMember(Name = "open_rate")>]
        OpenRate: float mcnull;
        [<field: DataMember(Name = "click_rate")>]
        ClickRate: float mcnull }

    [<DataContract(Namespace = "")>]
    type ListsDataItem =
      { [<field: DataMember(Name = "id")>]
        ListID: string;
        [<field: DataMember(Name = "web_id")>]
        WebID: int;
        [<field: DataMember(Name = "name")>]
        Name: string;
        [<field: DataMember(Name = "date_created")>]
        DataCreated: MCDateTime;
        [<field: DataMember(Name = "email_type_option")>]
        EmailTypeOption: MCBool;
        [<field: DataMember(Name = "use_awesomebar")>]
        UseAwesomeBar: MCBool;
        [<field: DataMember(Name = "default_from_name")>]
        DefaultFromName: string;
        [<field: DataMember(Name = "default_from_email")>]
        DefaultFromEmail: string;
        [<field: DataMember(Name = "default_subject")>]
        DefaultSubject: string;
        [<field: DataMember(Name = "default_language")>]
        DefaultLanguage: string;
        [<field: DataMember(Name = "list_rating")>]
        ListRating: float;
        [<field: DataMember(Name = "subscribe_url_short")>]
        SubscribeUrlShort: string;
        [<field: DataMember(Name = "subscribe_url_long")>]
        SubscribeUrlLong: string;
        [<field: DataMember(Name = "beamer_address")>]
        BeamerAddress: string;
        [<field: DataMember(Name = "visibility")>]
        Visibility: string;
        [<field: DataMember(Name = "stats")>]
        Stats: Stats;
        [<field: DataMember(Name = "modules")>]
        Modules: MCList<string> }

    [<DataContract(Namespace = "")>]
    type Lists =
      { [<field: DataMember(Name = "total")>]
        Total: int;
        [<field: DataMember(Name = "data")>]
        Data: MCList<ListsDataItem> }

    //------------------------------------------------------------------------------
    //  (*) Lists/Activity
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type ActivityItem =
      { [<field: DataMember(Name = "user_id")>]
        UserID: int;
        [<field: DataMember(Name = "day")>]
        Day: MCDateTime;
        [<field: DataMember(Name = "emails_sent")>]
        EmailsSent: int;
        [<field: DataMember(Name = "unique_opens")>]
        UniqueOpens: int;
        [<field: DataMember(Name = "recipient_clicks")>]
        RecipientClicks: int;
        [<field: DataMember(Name = "hard_bounce")>]
        HardBounce: int;
        [<field: DataMember(Name = "soft_bounce")>]
        SoftBounce: int;
        [<field: DataMember(Name = "abuse_reports")>]
        AbuseReports: int;
        [<field: DataMember(Name = "subs")>]
        Subs: int;
        [<field: DataMember(Name = "unsubs")>]
        Unsubs: int;
        [<field: DataMember(Name = "other_adds")>]
        OtherAdds: int;
        [<field: DataMember(Name = "other_removes")>]
        OtherRemoves: int }

    //------------------------------------------------------------------------------
    //  (*) Locations
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type Location =
      { [<field: DataMember(Name = "country")>]
        Country: string;
        [<field: DataMember(Name = "cc")>]
        CC: string;
        [<field: DataMember(Name = "percent")>]
        Percent: float;
        [<field: DataMember(Name = "total")>]
        Total: float }

    //------------------------------------------------------------------------------
    //  (*) Growth History
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type GrowthHistoryItem =
      { [<field: DataMember(Name = "month")>]
        Month: string;
        [<field: DataMember(Name = "existing")>]
        Existing: int;
        [<field: DataMember(Name = "imports")>]
        Imports: int;
        [<field: DataMember(Name = "optins")>]
        OptIns: int }

    //------------------------------------------------------------------------------
    //  (*) Clients
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type ClientData =
      { [<field: DataMember(Name = "client")>]
        Client: string;
        [<field: DataMember(Name = "icon")>]
        Icon: string;
        [<field: DataMember(Name = "percent")>]
        Percent: float;
        [<field: DataMember(Name = "members")>]
        Members: int }

    [<DataContract(Namespace = "")>]
    type AgentData =
      { [<field: DataMember(Name = "penetration")>]
        Penetration: float;
        [<field: DataMember(Name = "clients")>]
        Clients: MCList<ClientData> }

    [<DataContract(Namespace = "")>]
    type Clients =
      { [<field: DataMember(Name = "desktop")>]
        Desktop: AgentData;
        [<field: DataMember(Name = "mobile")>]
        Mobile:AgentData }

    //------------------------------------------------------------------------------
    //  (*) Interest Groupings
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type GroupingType =
        | [<EnumMember(Value = "checkboxes")>] Checkboxes = 0
        | [<EnumMember(Value = "radio")>] Radio = 1
        | [<EnumMember(Value = "dropdown")>] Dropdown = 2
        | [<EnumMember(Value = "hidden")>] Hidden = 3

    [<DataContract(Namespace = "")>]
    type InterestGroup =
      { [<field: DataMember(Name = "bit")>]
        Bit: string;
        [<field: DataMember(Name = "name")>]
        Name: string;
        [<field: DataMember(Name = "display_order")>]
        DisplayOrder: int;
        [<field: DataMember(Name = "subscribers")>]
        Subscribers: int }

    [<DataContract(Namespace = "")>]
    type InterestGrouping =
      { [<field: DataMember(Name = "id")>]
        ID: int;
        [<field: DataMember(Name = "name")>]
        Name: string;
        [<field: DataMember(Name = "form_field")>]
        FormField: GroupingType;
        [<field: DataMember(Name = "display_order")>]
        DisplayOrder: int;
        [<field: DataMember(Name = "groups")>]
        Groups: MCList<InterestGroup> }

    //------------------------------------------------------------------------------
    //  (*) Static Segments
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type StaticSegment =
      { [<field: DataMember(Name = "id")>]
        ID: int;
        [<field: DataMember(Name = "name")>]
        Name: string;
        [<field: DataMember(Name = "member_count")>]
        MemberCount: int;
        [<field: DataMember(Name = "created_date")>]
        CreatedDate: MCDateTime;
        [<field: DataMember(Name = "last_update")>]
        LastUpdate: MCDateTime;
        [<field: DataMember(Name = "last_reset")>]
        LastReset: MCDateTime }

    //------------------------------------------------------------------------------
    //  (*) Static Segment Members Action (Add/Del)
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type StaticSegmentMembersOpError =
     { [<field: DataMember(Name = "email")>]
        Email: string;
        [<field: DataMember(Name = "code")>]
        Code: int;
        [<field: DataMember(Name = "msg")>]
        Message: string }

    [<DataContract(Namespace = "")>]
    type StaticSegmentMembersOpResult =
      { [<field: DataMember(Name = "success")>]
        Success: int;
        [<field: DataMember(Name = "errors")>]
        Errors: MCList<StaticSegmentMembersOpError> }

    //------------------------------------------------------------------------------
    //  (*) Members
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type MemberStatus =
        | [<EnumMember(Value = "subscribed")>] Subscribed = 0
        | [<EnumMember(Value = "unsubscribed")>] Unsubscribed = 1
        | [<EnumMember(Value = "cleaned")>] Cleaned = 2
        | [<EnumMember(Value = "updated")>] Updated = 3

    [<DataContract(Namespace = "")>]
    type UnsubscribeReason =
        | [<EnumMember(Value = "NORMAL")>] Normal = 0
        | [<EnumMember(Value = "NOSIGNUP")>] NoSignup = 1
        | [<EnumMember(Value = "INAPPROPRIATE")>] Inappropriate = 2
        | [<EnumMember(Value = "SPAM")>] Spam = 3
        | [<EnumMember(Value = "OTHER")>] Other = 4

    [<DataContract(Namespace = "")>]
    type MembersDataItem =
      { [<field: DataMember(Name = "email")>]
        Email: string;
        [<field: DataMember(Name = "timestamp")>]
        Timestamp: MCDateTime;
        [<field: DataMember(Name = "reason")>]
        Reason: UnsubscribeReason mcnull;
        [<field: DataMember(Name = "reason_text")>]
        Description: string }

    [<DataContract(Namespace = "")>]
    type Members =
      { [<field: DataMember(Name = "total")>]
        Total: int;
        [<field: DataMember(Name = "data")>]
        Data: MCList<MembersDataItem> }

    //------------------------------------------------------------------------------
    //  (*) Member Info
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type EmailType =
        | [<EnumMember(Value = "html")>] Html = 0
        | [<EnumMember(Value = "text")>] Text = 1
        | [<EnumMember(Value = "mobile")>] Mobile = 2

    [<DataContract(Namespace = "")>]
    type Grouping =
        [<field: DataMember(Name = "id")>]
        val mutable ID: int mcnull
        [<field: DataMember(Name = "name")>]
        val mutable Name: string
        val mutable Groups: string[]

        private new(id, name, groups) = { ID = id; Name = name; Groups = groups }
        new(id, groups) = Grouping(MCNull id, null, groups)
        new(name, groups) = Grouping(MCNull<int>(), name, groups)

        [<property: DataMember(Name = "groups")>]
        member private x.groups
            with get() = IH.joinSeq ", " x.Groups
            and set(v) = x.Groups <- IH.split "," v

        override x.ToString() =
            String.Format("{{ID = {0}; Name = {1}; Groups = [{2}]}}",
                x.ID, x.Name, x.groups)

        interface IInput with
            member x.ToInput() = IH.build x

    [<DataContract(Namespace = "")>]
    type Address() =
        [<DefaultValue; field: DataMember(Name = "addr1")>]
        val mutable Address1: string
        [<DefaultValue; field: DataMember(Name = "addr2")>]
        val mutable Address2: string
        [<DefaultValue; field: DataMember(Name = "city")>]
        val mutable City: string
        [<DefaultValue; field: DataMember(Name = "state")>]
        val mutable State: string
        [<DefaultValue; field: DataMember(Name = "zip")>]
        val mutable Zip: string
        [<DefaultValue; field: DataMember(Name = "country")>]
        val mutable Country: string

        interface IInput with
            member x.ToInput() = IH.build x

    [<DataContract(Namespace = "")>]
    type MCLocation =
      { [<field: DataMember(Name = "LATITUDE")>]
        Latitude: float;
        [<field: DataMember(Name = "LONGITUDE")>]
        Longitude: float }

        static member Create(v) =
          { Latitude = fst v; Longitude = snd v }

        interface IInput with
            member x.ToInput() = IH.build x

    [<DataContract(Namespace = "")>]
    type MonthDay =
      { [<field: DataMember(Name = "month")>]
        Month: int;
        [<field: DataMember(Name = "day")>]
        Day: int }

        static member Create(month, day) =
          { Month = month; Day = day }

        interface IInput with
            member x.ToInput() = IH.build x

    [<DataContract(Namespace = "")>]
    type NoteAction =
        | [<EnumMember(Value = "append")>] Append = 0
        | [<EnumMember(Value = "prepend")>] Prepend = 1
        | [<EnumMember(Value = "replace")>] Replace = 2
        | [<EnumMember(Value = "delete")>] Delete = 3

    [<DataContract(Namespace = "")>]
    type MCNote() =
        [<DefaultValue; field: DataMember(Name = "id")>]
        val mutable ID: int opt
        [<DefaultValue; field: DataMember(Name = "note")>]
        val mutable Note: string
        [<DefaultValue; field: DataMember(Name = "update")>]
        val mutable Action: NoteAction opt

        interface IInput with
            member x.ToInput() = IH.build x

    /// Represents a collection of merge fields.
    type Merges() =
        inherit Input()

        new(email, emailType, [<op>]groupings) as x = Merges() then
            x.Email <- email
            x.EmailType <- emailType
            x.Groupings <- groupings
            ()

        new(email, emailType, ?groupings) =
            Merges(email, emailType, (<?)groupings)

        member private x.GetValue<'T>(v) =
            try x.[v] :?> 'T |> Some with _ -> None

        member private x.SetValue<'T>(item, v: 'T opt) =
            match v with
            | None -> x.Remove(item)
            | Some v -> x.[item] <- v

        member x.Email
            with get()  = x.GetValue<string>("EMAIL")
            and  set(v) = x.SetValue<string>("EMAIL", v)

        member x.EmailType
            with get()  = x.GetValue<EmailType>("EMAIL_TYPE")
            and  set(v) = x.SetValue<EmailType>("EMAIL_TYPE", v)

        member x.NewEmail
            with get()  = x.GetValue<string>("NEW-EMAIL")
            and  set(v) = x.SetValue<string>("NEW-EMAIL", v)

        member x.Groupings
            with get()  = x.GetValue<Grouping[]>("GROUPINGS")
            and  set(v) = x.SetValue<Grouping[]>("GROUPINGS", v)

        member x.OptInIP
            with get()  = x.GetValue<string>("OPTIN_IP")
            and  set(v) = x.SetValue<string>("OPTIN_IP", v)

        member x.OptInTime
            with get()  = x.GetValue<DateTime>("OPTIN_TIME")
            and  set(v) = x.SetValue<DateTime>("OPTIN_TIME", v)

        member x.MCLocation
            with get()  = x.GetValue<MCLocation>("MC_LOCATION")
            and  set(v) = x.SetValue<MCLocation>("MC_LOCATION", v)

        member x.MCLanguage
            with get()  = x.GetValue<string>("MC_LANGUAGE")
            and  set(v) = x.SetValue<string>("MC_LANGUAGE", v)

        member x.MCNotes
            with get()  = x.GetValue<MCNote>("MC_NOTES")
            and  set(v) = x.SetValue<MCNote>("MC_NOTES", v)

        interface IXmlSerializable with
            member IXmlSerializable.GetSchema() = null

            member x.WriteXml xw = ()

            member x.ReadXml xr =
                xr.MoveToContent() |> ignore
                let mutable s = xr.Read()
                while s do
                    if xr.NodeType = XmlNodeType.Element then
                        if xattr "type" xr = "array" then
                            match xr.LocalName.ToUpper() with
                            | "GROUPINGS" ->
                                let g = deserializeXml<MCList<Grouping>> xr
                                x.Groupings <- Array.ofSeq g |> Some
                            | "ADDRESS" | "MADDRESS" ->
                                x.[xr.LocalName] <- deserializeXml<Address> xr
                            | _ -> xr.Skip() // Unknown type
                        else x.[xr.LocalName] <- xr.ReadElementString()
                    else s <- xr.Read()


    [<DataContract(Namespace = "")>]
    type Geo =
      { [<field: DataMember(Name = "latitude")>]
        Latitude: float;
        [<field: DataMember(Name = "longitude")>]
        Longitude: float;
        [<field: DataMember(Name = "gmtoff")>]
        GmtOff: int;
        [<field: DataMember(Name = "dstoff")>]
        DstOff: int;
        [<field: DataMember(Name = "timezone")>]
        Timezone: string;
        [<field: DataMember(Name = "cc")>]
        CC: string;
        [<field: DataMember(Name = "region")>]
        Region: string }

    [<DataContract(Namespace = "")>]
    type MemberStaticSegment =
      { [<field: DataMember(Name = "id")>]
        ID: int;
        [<field: DataMember(Name = "name")>]
        Name: string;
        [<field: DataMember(Name = "added")>]
        Added: MCDateTime }

    [<DataContract(Namespace = "")>]
    type Client =
      { [<field: DataMember(Name = "name")>]
        Name: string;
        [<field: DataMember(Name = "icon_url")>]
        IconUrl: string }

    [<DataContract(Namespace = "")>]
    type Note =
      { [<field: DataMember(Name = "id")>]
        ID: int;
        [<field: DataMember(Name = "note")>]
        Note: string;
        [<field: DataMember(Name = "created")>]
        Created: MCDateTime;
        [<field: DataMember(Name = "updated")>]
        Updated: MCDateTime;
        [<field: DataMember(Name = "created_by_name")>]
        CreatedByName: string }

    [<DataContract(Namespace = "")>]
    type MemberInfoDataItem =
      { [<field: DataMember(Name = "id")>]
        ID: string;
        [<field: DataMember(Name = "email")>]
        Email: string;
        [<field: DataMember(Name = "email_type")>]
        EmailType: EmailType;
        [<field: DataMember(Name = "merges")>]
        Merges: Merges;
        [<field: DataMember(Name = "status")>]
        Status: string;
        [<field: DataMember(Name = "ip_signup")>]
        IP_Signup: string;
        [<field: DataMember(Name = "timestamp_signup")>]
        TimestampSignup: MCDateTime;
        [<field: DataMember(Name = "ip_opt")>]
        IP_Opt: string;
        [<field: DataMember(Name = "timestamp_opt")>]
        TimestampOpt: MCDateTime;
        [<field: DataMember(Name = "member_rating")>]
        MemberRating: int;
        [<field: DataMember(Name = "campaign_id")>]
        CampaignID: string;
        [<field: DataMember(Name = "lists")>]
        Lists: MCDict<string, string>;
        [<field: DataMember(Name = "timestamp")>]
        Timestamp: MCDateTime;
        [<field: DataMember(Name = "info_changed")>]
        InfoChanged: MCDateTime;
        [<field: DataMember(Name = "web_id")>]
        WebID: int;
        [<field: DataMember(Name = "is_gmonkey")>]
        IsGMonkey: MCBool;
        [<field: DataMember(Name = "language")>]
        Language: string;
        [<field: DataMember(Name = "geo")>]
        Geo: Geo;
        [<field: DataMember(Name = "clients")>]
        Clients: MCList<Client>;
        [<field: DataMember(Name = "static_segments")>]
        StaticSegments: MCList<MemberStaticSegment>
        [<field: DataMember(Name = "notes")>]
        Notes: MCList<Note> }

    [<DataContract(Namespace = "")>]
    type MemberInfo =
      { [<field: DataMember(Name = "success")>]
        Success: int mcnull;
        [<field: DataMember(Name = "errors")>]
        Errors: int mcnull;
        [<field: DataMember(Name = "data")>]
        Data: MCList<MemberInfoDataItem>;
        ErrorsData: MCList<EmailError> }

    //------------------------------------------------------------------------------
    //  (*) Member Activity
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type MemberActionType =
        | [<EnumMember(Value = "sent")>] Sent = 0
        | [<EnumMember(Value = "open")>] Open = 1
        | [<EnumMember(Value = "click")>] Click = 2
        | [<EnumMember(Value = "bounce")>] Bounce = 3
        | [<EnumMember(Value = "unsub")>] Unsub = 4
        | [<EnumMember(Value = "abuse")>] Abuse = 4

    [<DataContract(Namespace = "")>]
    type MemberAction =
      { [<field: DataMember(Name = "action")>]
        Action: MemberActionType;
        [<field: DataMember(Name = "timestamp")>]
        Timestamp: MCDateTime;
        [<field: DataMember(Name = "url")>]
        Url: string;
        [<field: DataMember(Name = "bounce_type")>]
        BounceType: string;
        [<field: DataMember(Name = "type")>]
        Type: string;
        [<field: DataMember(Name = "campaign_id")>]
        CampaignID: string }

    [<DataContract(Namespace = "")>]
    type MemberActivity =
      { [<field: DataMember(Name = "success")>]
        Success: int mcnull;
        [<field: DataMember(Name = "errors")>]
        Errors: int mcnull;
        [<field: DataMember(Name = "data")>]
        Data: MCList<MCList<MemberAction>>;
        ErrorsData: MCList<EmailError> }

    //------------------------------------------------------------------------------
    //  (*) Subscribe/Unsubscribe
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type SubscribeOptions() =
        [<DefaultValue; field: DataMember(Name = "email_type")>]
        val mutable EmailType: EmailType opt;
        [<DefaultValue; field: DataMember(Name = "double_optin")>]
        val mutable DoubleOptIn: bool opt;
        [<DefaultValue; field: DataMember(Name = "update_existing")>]
        val mutable UpdateExisting: bool opt;
        [<DefaultValue; field: DataMember(Name = "replace_interests")>]
        val mutable ReplaceInterests: bool opt;
        [<DefaultValue; field: DataMember(Name = "send_welcome")>]
        val mutable SendWelcome: bool opt

        interface IInput with
            member x.ToInput() = IH.build x

    [<DataContract(Namespace = "")>]
    type UnsubscribeOptions() =
        [<DefaultValue; field: DataMember(Name = "delete_member")>]
        val mutable DeleteMember: bool opt;
        [<DefaultValue; field: DataMember(Name = "send_goodbye")>]
        val mutable SendGoodby: bool opt;
        [<DefaultValue; field: DataMember(Name = "send_notify")>]
        val mutable SendNotify: bool opt;

        interface IInput with
            member x.ToInput() = IH.build x

    [<DataContract(Namespace = "")>]
    type BatchError =
      { [<field: DataMember(Name = "code")>]
        Code: int;
        [<field: DataMember(Name = "message")>]
        Message: string;
        [<field: DataMember(Name = "email")>]
        Email: string }

    [<DataContract(Namespace = "")>]
    type BatchSubscribe =
      { [<field: DataMember(Name = "add_count")>]
        AddCount: int;
        [<field: DataMember(Name = "update_count")>]
        UpdateCount: int;
        [<field: DataMember(Name = "error_count")>]
        ErrorCount: int;
        [<field: DataMember(Name = "errors")>]
        Errors: MCList<BatchError> }

    [<DataContract(Namespace = "")>]
    type BatchUnsubscribe =
      { [<field: DataMember(Name = "success_count")>]
        SuccessCount: int;
        [<field: DataMember(Name = "error_count")>]
        ErrorCount: int;
        [<field: DataMember(Name = "errors")>]
        Errors: MCList<BatchError> }

    //------------------------------------------------------------------------------
    //  (*) Webhooks
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type WebhookActions() =
        [<field: DataMember(Name = "subscribe")>]
        let mutable subscribe = MCBool true
        [<field: DataMember(Name = "unsubscribe")>]
        let mutable unsubsc = MCBool true
        [<field: DataMember(Name = "profile")>]
        let mutable profile = MCBool true
        [<field: DataMember(Name = "cleaned")>]
        let mutable cleaned = MCBool true
        [<field: DataMember(Name = "upemail")>]
        let mutable upemail = MCBool true

        member x.Subscribe
            with get() = subscribe.Value and set(v) = subscribe <- MCBool v
        member x.Unsubscribe
            with get() = unsubsc.Value and set(v) = unsubsc <- MCBool v
        member x.Profile
            with get() = profile.Value and set(v) = profile <- MCBool v
        member x.Cleaned
            with get() = cleaned.Value and set(v) = cleaned <- MCBool v
        member x.UpEmail
            with get() = upemail.Value and set(v) = upemail <- MCBool v

        interface IInput with
            member x.ToInput() = IH.build x

    [<DataContract(Namespace = "")>]
    type WebhookSources() =
        [<field: DataMember(Name = "user")>]
        let mutable user = MCBool true
        [<field: DataMember(Name = "admin")>]
        let mutable admin = MCBool true
        [<field: DataMember(Name = "api")>]
        let mutable api = MCBool false

        member x.User
            with get() = user.Value and set(v) = user <- MCBool v
        member x.Admin
            with get() = admin.Value and set(v) = admin <- MCBool v
        member x.Api
            with get() = api.Value and set(v) = api <- MCBool v

        interface IInput with
            member x.ToInput() = IH.build x

    [<DataContract(Namespace = "")>]
    type Webhook =
      { [<field: DataMember(Name = "url")>]
        Url: string;
        [<field: DataMember(Name = "actions")>]
        Actions: WebhookActions;
        [<field: DataMember(Name = "sources")>]
        Sources: WebhookSources }

    //------------------------------------------------------------------------------
    //  (*) Merge Vars
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type FieldType =
        | [<EnumMember(Value = "text")>] Text = 0
        | [<EnumMember(Value = "email")>] Email = 1
        | [<EnumMember(Value = "number")>] Number = 2
        | [<EnumMember(Value = "radio")>] Radio = 3
        | [<EnumMember(Value = "dropdown")>] Dropdown = 4
        | [<EnumMember(Value = "date")>] Date = 5
        | [<EnumMember(Value = "address")>] Address = 6
        | [<EnumMember(Value = "phone")>] Phone = 7
        | [<EnumMember(Value = "url")>] Url = 8
        | [<EnumMember(Value = "imageurl")>] ImageUrl = 9
        | [<EnumMember(Value = "zip")>] Zip = 10
        | [<EnumMember(Value = "birthday")>] Birthday = 11

    [<DataContract(Namespace = "")>]
    type MergeVar =
      { [<field: DataMember(Name = "id")>]
        ID: int;
        [<field: DataMember(Name = "name")>]
        Name: string;
        [<field: DataMember(Name = "req")>]
        Required: MCBool;
        [<field: DataMember(Name = "field_type")>]
        FieldType: FieldType;
        [<field: DataMember(Name = "public")>]
        Public: MCBool;
        [<field: DataMember(Name = "show")>]
        Show: MCBool;
        [<field: DataMember(Name = "order")>]
        Order: int;
        [<field: DataMember(Name = "default")>]
        Default: string;
        [<field: DataMember(Name = "helptext")>]
        HelpText: string;
        [<field: DataMember(Name = "size")>]
        Size: int;
        [<field: DataMember(Name = "tag")>]
        Tag: string;
        [<field: DataMember(Name = "choices")>]
        Choices: MCList<string> }

    [<DataContract(Namespace = "")>]
    type MergeVarOptions() =
        [<DefaultValue; field: DataMember(Name = "field_type")>]
        val mutable FieldType: FieldType opt
        [<DefaultValue; field: DataMember(Name = "req")>]
        val mutable Required: bool opt
        [<DefaultValue; field: DataMember(Name = "public")>]
        val mutable Public: bool opt
        [<DefaultValue; field: DataMember(Name = "show")>]
        val mutable Show: bool opt
        [<DefaultValue; field: DataMember(Name = "default_value")>]
        val mutable Default: string
        [<DefaultValue; field: DataMember(Name = "choices")>]
        val mutable Choices: string[] opt
        [<DefaultValue; field: DataMember(Name = "dateformat")>]
        val mutable DateFormat: string
        [<DefaultValue; field: DataMember(Name = "phoneformat")>]
        val mutable PhoneFormat: string
        [<DefaultValue; field: DataMember(Name = "defaultcountry")>]
        val mutable DefaultCountry: string

        interface IInput with
            member x.ToInput() = IH.build x

    //------------------------------------------------------------------------------
    //  (*) Abuse Reports
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type AbuseReport =
      { [<field: DataMember(Name = "date")>]
        Date: MCDateTime;
        [<field: DataMember(Name = "email")>]
        Email: string;
        [<field: DataMember(Name = "campaign_id")>]
        CampaignID: string;
        [<field: DataMember(Name = "type")>]
        Type: string }

    [<DataContract(Namespace = "")>]
    type AbuseReports =
      { [<field: DataMember(Name = "total")>]
        Total: int;
        [<field: DataMember(Name = "data")>]
        Data: MCList<AbuseReport> }

//==================================================================================
//  Campaing section
//==================================================================================

module Campaign =

    //------------------------------------------------------------------------------
    //  (*) Campaigns
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type Type =
        | [<EnumMember(Value = "regular")>] Regular = 0
        | [<EnumMember(Value = "plaintext")>] PlainText = 1
        | [<EnumMember(Value = "absplit")>] ABSplit = 2
        | [<EnumMember(Value = "rss")>] RSS = 3
        | [<EnumMember(Value = "inspection")>] Inspection = 4
        | [<EnumMember(Value = "trans")>] Trans = 5
        | [<EnumMember(Value = "auto")>] Auto = 6

    [<DataContract(Namespace = "")>]
    type Status =
        | [<EnumMember(Value = "sent")>] Sent = 0
        | [<EnumMember(Value = "save")>] Save = 1
        | [<EnumMember(Value = "paused")>] Paused = 2
        | [<EnumMember(Value = "schedule")>] Schedule = 3
        | [<EnumMember(Value = "sending")>] Sending = 4

    [<DataContract(Namespace = "")>]
    type TestEmailType =
        | [<EnumMember(Value = "html")>] Html = 0
        | [<EnumMember(Value = "text")>] Text = 1

    [<DataContract(Namespace = "")>]
    type Filter() =
        [<DefaultValue; field: DataMember(Name = "campaign_id")>]
        val mutable CampaignID: string mcseq
        [<DefaultValue; field: DataMember(Name = "parent_id")>]
        val mutable ParentID: string mcseq
        [<DefaultValue; field: DataMember(Name = "list_id")>]
        val mutable ListID: string mcseq
        [<DefaultValue; field: DataMember(Name = "folder_id")>]
        val mutable FolderID: int mcseq
        [<DefaultValue; field: DataMember(Name = "template_id")>]
        val mutable TemplateID: int mcseq
        [<DefaultValue; field: DataMember(Name = "status")>]
        val mutable Status: Status mcseq
        [<DefaultValue; field: DataMember(Name = "type_id")>]
        val mutable Type: Type mcseq
        [<DefaultValue; field: DataMember(Name = "from_name")>]
        val mutable FromName: string
        [<DefaultValue; field: DataMember(Name = "from_email")>]
        val mutable FromEmail: string
        [<DefaultValue; field: DataMember(Name = "title")>]
        val mutable Title: string
        [<DefaultValue; field: DataMember(Name = "subject")>]
        val mutable Subject: string
        [<DefaultValue; field: DataMember(Name = "sendtime_start")>]
        val mutable SendtimeStart: DateTime opt
        [<DefaultValue; field: DataMember(Name = "sendtime_end")>]
        val mutable SendtimeEnd: DateTime opt
        [<DefaultValue; field: DataMember(Name = "uses_segment")>]
        val mutable UsesSegment: bool opt
        [<DefaultValue; field: DataMember(Name = "exact")>]
        val mutable Exact: bool opt

        interface IInput with
            member x.ToInput() = IH.build x

    //------------------------------------------------------------------------------
    //  (*) Segment Test
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type Match =
        | [<EnumMember(Value = "all")>] AND = 0
        | [<EnumMember(Value = "any")>] OR = 1

    type private SegmentValue(value) =
        inherit VarList<string, MCList<string>>(value)

        new() = SegmentValue(Null)

        interface IValue with
            member x.Value = x.Value |> box

    [<DataContract(Namespace = "")>]
    type SegmentCondition =
        [<field: DataMember(Name = "field")>]
        val mutable Field: string;
        [<field: DataMember(Name = "op")>]
        val mutable Op: string
        [<field: DataMember(Name = "value")>]
        val mutable private sValue: SegmentValue
        [<field: DataMember(Name = "extra")>]
        val mutable Extra: string

        new(field, op, value, extra) =
         { Field = field; Op = op; sValue = SegmentValue(value); Extra = extra }
        new(field, op, value) =
           SegmentCondition(field, op, value, null)

        member x.Value
            with get() = x.sValue.Value
            and set(v) = x.sValue.Value <- v

        member x.StringValue
            with get() = string x.sValue
            and set(v) = x.sValue.Value <- MCSeq.parse v

        override x.ToString() =
            let s = String.Format("{0} => {1} => {2}", x.Field, x.Op, x.sValue)
            if isNullOrEmpty x.Extra then s
            else String.Format("{0} => {1}", s, x.Extra);

        interface IInput with
            member x.ToInput() = IH.build x

    module private CndParser =

        let (|SC|_|) x =
            if not (isNullOrEmpty x) then
                let a = (regex @"\s*=>\s*").Split x
                match a.Length with
                | 3 -> SegmentCondition(a.[0], a.[1], MCSeq.parse a.[2]) |> Option.Some
                | 4 -> SegmentCondition(a.[0], a.[1], MCSeq.parse a.[2], a.[3]) |> Option.Some
                | _ -> Option.None
            else Option.None

        let parse (xs: string mcseq) =
            let v = match xs with
                    | Null -> [ ] :> seq<string>
                    | Sn v -> [v] :> seq<string>
                    | Sq v ->  v
            v |> Seq.choose (fun m -> match m with SC x -> Option.Some x | _ -> Option.None) |>
            MCList.ofSeq


    [<DataContract(Namespace = "")>]
    type SegmentOptions =
      { [<field: DataMember(Name = "match")>]
        Match: Match;
        [<field: DataMember(Name = "conditions")>]
        Conditions: MCList<SegmentCondition> }

        /// <summary>Parses a sequence of condition strings.
        /// <para>Condition format: "field => op => value [=> extra]"</para></summary>
        /// <remarks>Value containing unescaped commas will be splitted into an array.</remarks>
        static member Parse(m, xs) =
          { Match = m; Conditions = CndParser.parse xs }

        interface IInput with
            member x.ToInput() = IH.build x

    //------------------------------------------------------------------------------
    //  (*) Create
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type ArchiveType =
        | [<EnumMember(Value = "zip")>] Zip = 0
        | [<EnumMember(Value = "tar.gz")>] TarGZ = 1
        | [<EnumMember(Value = "tar.bz2")>] TarBZ2 = 2
        | [<EnumMember(Value = "tar")>] Tar = 3
        | [<EnumMember(Value = "tgz")>] Tgz = 4
        | [<EnumMember(Value = "tbz")>] Tbz = 5

    [<DataContract(Namespace = "")>]
    type ScheduleType =
        | [<EnumMember(Value = "daily")>] Daily = 0
        | [<EnumMember(Value = "weekly")>] Weekly = 1
        | [<EnumMember(Value = "monthly")>] Monthly = 2

    [<DataContract(Namespace = "")>]
    type SegmentOption =
        | [<EnumMember(Value = "subject")>] Subject = 0
        | [<EnumMember(Value = "from_name")>] FromName = 1
        | [<EnumMember(Value = "schedule")>] Schedule = 2

    [<DataContract(Namespace = "")>]
    type PickWinnersOption =
        | [<EnumMember(Value = "opens")>] Opens = 0
        | [<EnumMember(Value = "clicks")>] Clicks= 1
        | [<EnumMember(Value = "manual")>] Manual = 2

    [<DataContract(Namespace = "")>]
    type OffsetUnits =
        | [<EnumMember(Value = "day")>] Day = 0
        | [<EnumMember(Value = "week")>] Week = 1
        | [<EnumMember(Value = "month")>] Month = 2
        | [<EnumMember(Value = "year")>] Year = 3

    [<DataContract(Namespace = "")>]
    type OffsetDir =
        | [<EnumMember(Value = "before")>] Before = 0
        | [<EnumMember(Value = "after")>] After = 1

    [<DataContract(Namespace = "")>]
    type EventType  =
        | [<EnumMember(Value = "signup")>] Signup = 0
        | [<EnumMember(Value = "date")>] Date = 1
        | [<EnumMember(Value = "annual")>] Annual = 2
        | [<EnumMember(Value = "birthday")>] Birthday = 3
        | [<EnumMember(Value = "campaignOpen")>] CampaignOpen = 4
        | [<EnumMember(Value = "campaignClicka")>] CampaignClicka = 5
        | [<EnumMember(Value = "campaignClicko")>] CampaignClicko = 6
        | [<EnumMember(Value = "mergeChanged")>] MergeChanged = 7

    [<DataContract(Namespace = "")>]
    type Tracking() =
        [<field: DataMember(Name = "html_clicks")>]
        let mutable htmlClicks = MCBool true
        [<field: DataMember(Name = "text_clicks")>]
        let mutable textClicks = MCBool true
        [<field: DataMember(Name = "opens")>]
        let mutable opens = MCBool true

        member x.HtmlClicks
            with get() = htmlClicks.Value and set(v) = htmlClicks <- MCBool v
        member x.TextClicks
            with get() = textClicks.Value and set(v) = textClicks <- MCBool v
        member x.Opens
            with get() = opens.Value and set(v) = opens <- MCBool v

        interface IInput with
            member x.ToInput() = IH.build x

    [<DataContract(Namespace = "")>]
    type CrmTrackingOpts =
      { [<field: DataMember(Name = "campaign")>]
        mutable Campaign: bool opt;
        [<field: DataMember(Name = "notes")>]
        mutable Notes: bool opt }

        static member Create(campaign, notes) =
          { Campaign = Some campaign; Notes = Some notes }

        static member Create(notes) =
          { Campaign = None; Notes = Some notes }

        interface IInput with
            member x.ToInput() = IH.build x

    [<DataContract(Namespace = "")>]
    type CrmTracking =
        [<field: DataMember(Name = "salesforce")>]
        val mutable Salesforce: CrmTrackingOpts opt
        [<field: DataMember(Name = "highrise")>]
        val mutable Highrise: CrmTrackingOpts opt
        [<field: DataMember(Name = "capsule")>]
        val mutable Capsule: CrmTrackingOpts opt

        interface IInput with
            member x.ToInput() = IH.build x

    [<DataContract(Namespace = "")>]
    type Options(listID, subject, fromEmail, fromName, toName) =
        [<property: DataMember(Name = "list_id")>]
        member x.ListID: string = listID
        [<property: DataMember(Name = "subject")>]
        member x.Subject: string = subject
        [<property: DataMember(Name = "from_email")>]
        member x.FromEmail: string = fromEmail
        [<property: DataMember(Name = "from_name")>]
        member x.FromName: string = fromName
        [<property: DataMember(Name = "to_name")>]
        member x.ToName: string = toName
        [<DefaultValue; field: DataMember(Name = "template_id")>]
        val mutable TemplateID: int opt
        [<DefaultValue; field: DataMember(Name = "gallery_template_id")>]
        val mutable GalleryTemplateID: int opt
        [<DefaultValue; field: DataMember(Name = "base_template_id")>]
        val mutable BaseTemplateID: int opt
        [<DefaultValue; field: DataMember(Name = "folder_id")>]
        val mutable FolderID: int opt
        [<DefaultValue; field: DataMember(Name = "tracking")>]
        val mutable Tracking: Tracking opt
        [<DefaultValue; field: DataMember(Name = "title")>]
        val mutable Title: string
        [<DefaultValue; field: DataMember(Name = "authenticate")>]
        val mutable Authenticate: bool opt
        [<DefaultValue; field: DataMember(Name = "analytics")>]
        val mutable Analytics: Input opt
        [<DefaultValue; field: DataMember(Name = "auto_footer")>]
        val mutable AutoFooter: bool opt
        [<DefaultValue; field: DataMember(Name = "inline_css")>]
        val mutable InlineCss: bool opt
        [<DefaultValue; field: DataMember(Name = "generate_text")>]
        val mutable GenerateText: bool opt
        [<DefaultValue; field: DataMember(Name = "auto_tweet")>]
        val mutable AutoTweet: bool opt
        [<DefaultValue; field: DataMember(Name = "auto_fb_post")>]
        val mutable AutoFbPost: string[] opt
        [<DefaultValue; field: DataMember(Name = "fb_comments")>]
        val mutable FbComments: bool opt
        [<DefaultValue; field: DataMember(Name = "timewarp")>]
        val mutable Timewarp: bool opt
        [<DefaultValue; field: DataMember(Name = "ecomm360")>]
        val mutable Ecomm360: bool opt
        [<DefaultValue; field: DataMember(Name = "crm_tracking")>]
        val mutable CrmTracking: CrmTracking opt

        interface IInput with
            member x.ToInput() = IH.build x

    module TypeOptions =

        module private Helper =

            open System.Linq

            let getExDays (days: #seq<DayOfWeek> opt) =
                let f xs =
                    let ex = xs |> Seq.map (fun z -> isoWeekDay z)
                    [| 1 .. 7 |].Except(ex).ToDictionary((fun k -> k), (fun _ -> false))
                match days with None -> None | Some v -> f v |> Some


        [<AbstractClass>]
        [<DataContract(Namespace = "")>]
        type Base() =

            interface IInput with
                member x.ToInput() = IH.build x

        [<DataContract(Namespace = "")>]
        type Rss() =
            inherit Base()
            [<DefaultValue; field: DataMember(Name = "url")>]
            val mutable Url: string
            [<DefaultValue; field: DataMember(Name = "schedule")>]
            val mutable Schedule: ScheduleType opt
            [<DefaultValue; field: DataMember(Name = "schedule_hour")>]
            val mutable ScheduleHour: int opt
            [<DefaultValue; field: DataMember(Name = "schedule_weekday")>]
            val mutable ScheduleWeekday: int opt
            [<DefaultValue; field: DataMember(Name = "schedule_monthday")>]
            val mutable ScheduleMonthday: int opt
            [<DefaultValue>]
            val mutable Days: DayOfWeek[] opt

            [<property: DataMember(Name = "days")>]
            member private x.ExDays = Helper.getExDays x.Days

        [<DataContract(Namespace = "")>]
        type AbSplit() =
            inherit Base()
            [<DefaultValue; field: DataMember(Name = "split_test")>]
            val mutable SplitTest: SegmentOption
            [<DefaultValue; field: DataMember(Name = "pick_winner")>]
            val mutable PickWinner: PickWinnersOption
            [<DefaultValue; field: DataMember(Name = "wait_units")>]
            val mutable WaitUnits: int opt
            [<DefaultValue; field: DataMember(Name = "wait_time")>]
            val mutable WaitTime: int opt
            [<DefaultValue; field: DataMember(Name = "split_size")>]
            val mutable SplitSize: int opt
            [<DefaultValue; field: DataMember(Name = "from_name_a")>]
            val mutable FromNameA: string
            [<DefaultValue; field: DataMember(Name = "from_name_b")>]
            val mutable FromNameB: string
            [<DefaultValue; field: DataMember(Name = "from_email_a")>]
            val mutable FromEmailA: string
            [<DefaultValue; field: DataMember(Name = "from_email_b")>]
            val mutable FromEmailB: string
            [<DefaultValue; field: DataMember(Name = "subject_a")>]
            val mutable SubjectA: string
            [<DefaultValue; field: DataMember(Name = "subject_b")>]
            val mutable SubjectB: string

        [<DataContract(Namespace = "")>]
        type AutoResponder() =
            inherit Base()
            [<DefaultValue; field: DataMember(Name = "offset-units")>]
            val mutable OffsetUnits: OffsetUnits
            [<DefaultValue; field: DataMember(Name = "offset-time")>]
            val mutable OffsetTime: int opt
            [<DefaultValue; field: DataMember(Name = "offset-dir")>]
            val mutable OffsetDir: OffsetDir
            [<DefaultValue; field: DataMember(Name = "event")>]
            val mutable Event: EventType opt
            [<DefaultValue; field: DataMember(Name = "event-datemerge")>]
            val mutable EventDatemerge: string
            [<DefaultValue; field: DataMember(Name = "campaign_id")>]
            val mutable CampaignID: string
            [<DefaultValue; field: DataMember(Name = "campaign_url")>]
            val mutable CampaignUrl: string
            [<DefaultValue; field: DataMember(Name = "schedule_hour")>]
            val mutable ScheduleHour: int
            [<DefaultValue; field: DataMember(Name = "use_import_time")>]
            val mutable UseImportTime: bool
            [<DefaultValue>]
            val mutable Days: DayOfWeek[] opt

            [<property: DataMember(Name = "days")>]
            member private x.ExDays = Helper.getExDays x.Days

    //------------------------------------------------------------------------------
    //  (*) Campaign Content
    //------------------------------------------------------------------------------

    module Content =

        [<DataContract(Namespace = "")>]
        type Base() =
            [<field: DataMember(Name = "text")>]
            let mutable text: string = null

            member x.Text with get() = text and set(v) = text <- v

            interface IInput with
                member x.ToInput() = IH.build x

        [<DataContract(Namespace = "")>]
        type Html() =
            inherit Base()
            [<DefaultValue; field: DataMember(Name = "html")>]
            val mutable Html: string
            [<DefaultValue; field: DataMember(Name = "url")>]
            val mutable Url: string

            [<property: DataMember(Name = "text")>]
            member x.Text
                with get() = base.Text and set(v) = base.Text <- v

        [<DataContract(Namespace = "")>]
        type Archive() =
            inherit Base()
            [<DefaultValue; field: DataMember(Name = "archive")>]
            val mutable Archive: string
            [<DefaultValue; field: DataMember(Name = "archive_type")>]
            val mutable ArchiveType: ArchiveType

        [<DataContract(Namespace = "")>]
        type Template() =
            inherit Base()
            let cs = MCDict<string>()
            let getValue x =
                if cs.ContainsKey(x) then cs.[x] else null

            member x.Sections with get() = cs
            member x.Header
                with get() = getValue "header"
                and set(v) = cs.["header"] <- v
            member x.HeaderImage
                with get() = getValue "header_image"
                and set(v) = cs.["header_image"] <- v
            member x.Main
                with get() = getValue "main"
                and set(v) = cs.["main"] <- v
             member x.SideColumn
                with get() = getValue "sidecolumn"
                and set(v) = cs.["sidecolumn"] <- v
            member x.Footer
                with get() = getValue "footer"
                and set(v) = cs.["footer"] <- v

            member x.Merge replace (ts: MCDict<string>) =
                ts |> Seq.iter(fun s ->
                    if replace || not (cs.ContainsKey(s.Key)) then
                        cs.[s.Key] <- s.Value)

            interface IInput with
                member x.ToInput() =
                    let keyf (k: string) = "html_" + k.ToLower()
                    Input.ofDict keyf cs

    //------------------------------------------------------------------------------
    //  (*) Campaigns
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type ContentType =
        | [<EnumMember(Value = "html")>] Html = 0
        | [<EnumMember(Value = "template")>] Template = 1
        | [<EnumMember(Value = "url")>] Url = 2
        | [<EnumMember(Value = "cid")>] CID = 3
        | [<EnumMember(Value = "tid")>] TID = 4

    [<DataContract(Namespace = "")>]
    type CampaignsDataItem =
      { [<field: DataMember(Name = "id")>]
        ID: string;
        [<field: DataMember(Name = "web_id")>]
        WebID: int;
        [<field: DataMember(Name = "parent_id")>]
        ParentID: string;
        [<field: DataMember(Name = "list_id")>]
        ListID: string;
        [<field: DataMember(Name = "folder_id")>]
        FolderID: int;
        [<field: DataMember(Name = "template_id")>]
        TemplateID: int;
        [<field: DataMember(Name = "content_type")>]
        ContentType: ContentType;
        [<field: DataMember(Name = "title")>]
        Title: string;
        [<field: DataMember(Name = "type")>]
        Type: Type;
        [<field: DataMember(Name = "create_time")>]
        CreateTime: MCDateTime;
        [<field: DataMember(Name = "send_time")>]
        SendTime: MCDateTime;
        [<field: DataMember(Name = "status")>]
        Status: Status;
        [<field: DataMember(Name = "from_name")>]
        FromName: string;
        [<field: DataMember(Name = "from_email")>]
        FromEmail: string;
        [<field: DataMember(Name = "subject")>]
        Subject: string;
        [<field: DataMember(Name = "to_name")>]
        ToName: string;
        [<field: DataMember(Name = "archive_url")>]
        ArchiveUrl: string;
        [<field: DataMember(Name = "emails_sent")>]
        EmailsSent: int;
        [<field: DataMember(Name = "inline_css")>]
        InlineCss: MCBool;
        [<field: DataMember(Name = "inline_css2")>]
        InlineCss2: MCBool;
        [<field: DataMember(Name = "analytics")>]
        Analytics: string;
        [<field: DataMember(Name = "analytics_tag")>]
        AnalyticsTag: string;
        [<field: DataMember(Name = "authenticate")>]
        Authenticate: MCBool;
        [<field: DataMember(Name = "ecomm360")>]
        Ecomm360: MCBool;
        [<field: DataMember(Name = "auto_tweet")>]
        AutoTweet: MCBool;
        [<field: DataMember(Name = "auto_fb_post")>]
        AutoFbPost: string;
        [<field: DataMember(Name = "auto_footer")>]
        AutoFooter: MCBool;
        [<field: DataMember(Name = "timewarp")>]
        Timewarp: MCBool;
        [<field: DataMember(Name = "timewarp_schedule")>]
        TimewarpSchedule: MCDateTime;
        [<field: DataMember(Name = "tracking")>]
        Tracking: Tracking;
        [<field: DataMember(Name = "segment_text")>]
        SegmentText: string;
        [<field: DataMember(Name = "segment_opts")>]
        SegmentOpts: SegmentOptions;
        [<field: DataMember(Name = "type_opts")>]
        TypeOpts: MCDict<string> }

    [<DataContract(Namespace = "")>]
    type Campaigns =
      { [<field: DataMember(Name = "total")>]
        Total: int;
        [<field: DataMember(Name = "data")>]
        Data: MCList<CampaignsDataItem> }

    [<DataContract(Namespace = "")>]
    type CampaignsForEmailItem =
      { [<field: DataMember(Name = "id")>]
        ID: string;
        [<field: DataMember(Name = "type")>]
        Type: Type;
        [<field: DataMember(Name = "title")>]
        Title: string;
        [<field: DataMember(Name = "subject")>]
        Subject: string;
        [<field: DataMember(Name = "send_time")>]
        SendTime: MCDateTime }

    //------------------------------------------------------------------------------
    //  (*) ShareReport
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type ShareReportOptions() =
        [<DefaultValue; field: DataMember(Name = "to_email")>]
        val mutable ToEmail: string
        [<DefaultValue; field: DataMember(Name = "company")>]
        val mutable Company: string
        [<DefaultValue; field: DataMember(Name = "theme_id")>]
        val mutable ThemeID: int opt
        [<DefaultValue; field: DataMember(Name = "css_url")>]
        val mutable CssUrl: string

        interface IInput with
            member x.ToInput() = IH.build x

    [<DataContract(Namespace = "")>]
    type ShareReport =
      { [<field: DataMember(Name = "title")>]
        Title: string;
        [<field: DataMember(Name = "url")>]
        Url: string;
        [<field: DataMember(Name = "secure_url")>]
        SecureUrl: string;
        [<field: DataMember(Name = "password")>]
        Password: string }

//==================================================================================
//  Campaing stats section
//==================================================================================

    module Stats =

    //------------------------------------------------------------------------------
    //  (*) Stats
    //------------------------------------------------------------------------------

        [<DataContract(Namespace = "")>]
        type Absplit =
          { [<field: DataMember(Name = "bounces_a")>]
            BouncesA: int;
            [<field: DataMember(Name = "bounces_b")>]
            BouncesB: int;
            [<field: DataMember(Name = "forwards_a")>]
            ForwardsA: int;
            [<field: DataMember(Name = "forwards_b")>]
            ForwardsB: int;
            [<field: DataMember(Name = "abuse_reports_a")>]
            AbuseReportsA: int;
            [<field: DataMember(Name = "abuse_reports_b")>]
            AbuseReportsB: int;
            [<field: DataMember(Name = "unsubs_a")>]
            UnsubsA: int;
            [<field: DataMember(Name = "unsubs_b")>]
            UnsubsB: int;
            [<field: DataMember(Name = "recipients_click_a")>]
            RecipientsClickA: int;
            [<field: DataMember(Name = "recipients_click_b")>]
            RecipientsClickB: int;
            [<field: DataMember(Name = "forwards_opens_a")>]
            ForwardsOpensA: int;
            [<field: DataMember(Name = "forwards_opens_b")>]
            ForwardsOpensB: int }

        [<DataContract(Namespace = "")>]
        type TimezoneStats =
          { [<field: DataMember(Name = "opens")>]
            Opens: int;
            [<field: DataMember(Name = "last_open")>]
            LastOpen: MCDateTime;
            [<field: DataMember(Name = "unique_opens")>]
            UniqueOpens: int;
            [<field: DataMember(Name = "clicks")>]
            Clicks: int;
            [<field: DataMember(Name = "last_click")>]
            LastClick: MCDateTime;
            [<field: DataMember(Name = "unique_clicks")>]
            UniqueClicks: int;
            [<field: DataMember(Name = "bounces")>]
            Bounces: int;
            [<field: DataMember(Name = "total")>]
            Total: int;
            [<field: DataMember(Name = "sent")>]
            Sent: int }

        [<DataContract(Namespace = "")>]
        type Stats =
          { [<field: DataMember(Name = "syntax_errors")>]
            SyntaxErrors: int;
            [<field: DataMember(Name = "hard_bounces")>]
            HardBounces: int;
            [<field: DataMember(Name = "soft_bounces")>]
            SoftBounces: int;
            [<field: DataMember(Name = "unsubscribes")>]
            Unsubscribes: int;
            [<field: DataMember(Name = "abuse_reports")>]
            AbuseReports: int;
            [<field: DataMember(Name = "forwards")>]
            Forwards: int;
            [<field: DataMember(Name = "forwards_opens")>]
            ForwardsOpens: int;
            [<field: DataMember(Name = "opens")>]
            Opens: int;
            [<field: DataMember(Name = "last_open")>]
            LastOpen: MCDateTime;
            [<field: DataMember(Name = "unique_opens")>]
            UniqueOpens: int;
            [<field: DataMember(Name = "clicks")>]
            Clicks: int;
            [<field: DataMember(Name = "unique_clicks")>]
            UniqueClicks: int;
            [<field: DataMember(Name = "users_who_clicked")>]
            UniqueWhoClicked: int;
            [<field: DataMember(Name = "last_click")>]
            LastClick: MCDateTime;
            [<field: DataMember(Name = "emails_sent")>]
            EmailsSent: int;
            [<field: DataMember(Name = "absplit")>]
            Absplit: Absplit;
            [<field: DataMember(Name = "timewarp")>]
            Timewarp: MCDict<int, TimezoneStats> }

    //------------------------------------------------------------------------------
    //  (*) Abuse Reports
    //------------------------------------------------------------------------------

        [<DataContract(Namespace = "")>]
        type AbuseReport =
          { [<field: DataMember(Name = "date")>]
            Date: MCDateTime;
            [<field: DataMember(Name = "email")>]
            Email: string;
            [<field: DataMember(Name = "type")>]
            Type: string }

    //------------------------------------------------------------------------------
    //  (*) Members
    //------------------------------------------------------------------------------

        [<DataContract(Namespace = "")>]
        type SendStatus =
            | [<EnumMember(Value = "sent")>] Sent = 0
            | [<EnumMember(Value = "hard")>] Hard = 1
            | [<EnumMember(Value = "soft")>] Soft = 2

        [<DataContract(Namespace = "")>]
        type MembersDataItem =
          { [<field: DataMember(Name = "email")>]
            Email: string;
            [<field: DataMember(Name = "status")>]
            Status: SendStatus;
            [<field: DataMember(Name = "absplit_group")>]
            AbsplitGroup: string;
            [<field: DataMember(Name = "tz_group")>]
            TimezoneGroup: string }

        [<DataContract(Namespace = "")>]
        type Members =
          { [<field: DataMember(Name = "total")>]
            Total: int;
            [<field: DataMember(Name = "data")>]
            Data: MCList<MembersDataItem> }

    //------------------------------------------------------------------------------
    //  (*) Advice
    //------------------------------------------------------------------------------

        [<DataContract(Namespace = "")>]
        type MessageType =
            | [<EnumMember(Value = "neutral")>] Neutral = 0
            | [<EnumMember(Value = "negative")>] Negative = 1
            | [<EnumMember(Value = "positive")>] Positive = 2

        [<DataContract(Namespace = "")>]
        type Advice =
          { [<field: DataMember(Name = "msg")>]
            Message: string;
            [<field: DataMember(Name = "type")>]
            Type: MessageType }

    //------------------------------------------------------------------------------
    //  (*) Analytics
    //------------------------------------------------------------------------------

        [<DataContract(Namespace = "")>]
        type AnalyticsGoal =
          { [<field: DataMember(Name = "name")>]
            Name: string;
            [<field: DataMember(Name = "conversions")>]
            Conversions: string }

        [<DataContract(Namespace = "")>]
        type Analytics =
          { [<field: DataMember(Name = "visits")>]
            Visits: int;
            [<field: DataMember(Name = "pages")>]
            Pages: int;
            [<field: DataMember(Name = "new_visits")>]
            NewVisits: int;
            [<field: DataMember(Name = "bounces")>]
            Bounces: int;
            [<field: DataMember(Name = "time_on_site")>]
            TimeOnSite: float;
            [<field: DataMember(Name = "goal_conversions")>]
            GoalConversions: int;
            [<field: DataMember(Name = "goal_value")>]
            GoalValue: float;
            [<field: DataMember(Name = "revenue")>]
            Revenue: float;
            [<field: DataMember(Name = "transactions")>]
            Transactions: int;
            [<field: DataMember(Name = "ecomm_conversions")>]
            EcommConversions: int;
            [<field: DataMember(Name = "goals")>]
            Goals: MCList<AnalyticsGoal> }

    //------------------------------------------------------------------------------
    //  (*) Bounce Messages
    //------------------------------------------------------------------------------

        [<DataContract(Namespace = "")>]
        type BounceMessage =
          { [<field: DataMember(Name = "date")>]
            Date: MCDateTime;
            [<field: DataMember(Name = "email")>]
            Email: string;
            [<field: DataMember(Name = "message")>]
            Message: string }

        [<DataContract(Namespace = "")>]
        type BounceMessages =
          { [<field: DataMember(Name = "total")>]
            Total: int;
            [<field: DataMember(Name = "data")>]
            Data: MCList<BounceMessage> }

    //------------------------------------------------------------------------------
    //  (*) Click Stats
    //------------------------------------------------------------------------------

        [<DataContract(Namespace = "")>]
        type ClickStats =
          { [<field: DataMember(Name = "clicks")>]
            Clicks: int;
            [<field: DataMember(Name = "unique")>]
            Unique: int }

    //------------------------------------------------------------------------------
    //  (*) Eep Url Stats
    //------------------------------------------------------------------------------

        [<DataContract(Namespace = "")>]
        type TwitterStatus =
          { [<field: DataMember(Name = "status")>]
            Status: string;
            [<field: DataMember(Name = "screen_name")>]
            ScreenName: string;
            [<field: DataMember(Name = "status_id")>]
            StatusID: string;
            [<field: DataMember(Name = "datetime")>]
            Datetime: MCDateTime;
            [<field: DataMember(Name = "is_retweet")>]
            IsRetweet: MCBool }

        [<DataContract(Namespace = "")>]
        type Twitter =
          { [<field: DataMember(Name = "tweets")>]
            Tweets: int;
            [<field: DataMember(Name = "first_tweet")>]
            FirstTweet: MCDateTime;
            [<field: DataMember(Name = "last_tweet")>]
            LastTweet: MCDateTime;
            [<field: DataMember(Name = "retweets")>]
            Retweets: int;
            [<field: DataMember(Name = "first_retweet")>]
            FirstRetweet: MCDateTime;
            [<field: DataMember(Name = "last_retweet")>]
            LastRetweet: MCDateTime;
            [<field: DataMember(Name = "statuses")>]
            Statuses: MCList<TwitterStatus> }

        [<DataContract(Namespace = "")>]
        type ClickLocation =
          { [<field: DataMember(Name = "country")>]
            Country: string;
            [<field: DataMember(Name = "region")>]
            Region: string;
            [<field: DataMember(Name = "clicks")>]
            Clicks: int }

        [<DataContract(Namespace = "")>]
        type Clicks =
          { [<field: DataMember(Name = "clicks")>]
            Clicks: int;
            [<field: DataMember(Name = "first_click")>]
            FirstClick: MCDateTime;
            [<field: DataMember(Name = "last_click")>]
            LastClick: MCDateTime;
            [<field: DataMember(Name = "locations")>]
            Locations: MCList<ClickLocation> }

        [<DataContract(Namespace = "")>]
        type Referrer =
          { [<field: DataMember(Name = "referrer")>]
            Referrer: string;
            [<field: DataMember(Name = "clicks")>]
            Clicks: int;
            [<field: DataMember(Name = "first_click")>]
            FirstClick: MCDateTime;
            [<field: DataMember(Name = "last_click")>]
            LastClick: MCDateTime }

        [<DataContract(Namespace = "")>]
        type EepUrlStats =
          { [<field: DataMember(Name = "twitter")>]
            Twitter: Twitter;
            [<field: DataMember(Name = "click")>]
            Clicks: Clicks;
            [<field: DataMember(Name = "referrers")>]
            Referrers: MCList<Referrer> }

    //------------------------------------------------------------------------------
    //  (*) Email Domain Performance
    //------------------------------------------------------------------------------

        [<DataContract(Namespace = "")>]
        type EmailDomainPerformance =
          { [<field: DataMember(Name = "domain")>]
            Domain: string;
            [<field: DataMember(Name = "total_sent")>]
            TotalSent: int;
            [<field: DataMember(Name = "emails")>]
            Emails: int;
            [<field: DataMember(Name = "bounces")>]
            Bounces: int;
            [<field: DataMember(Name = "opens")>]
            Opens: int;
            [<field: DataMember(Name = "clicks")>]
            Clicks: int;
            [<field: DataMember(Name = "unsubs")>]
            Unsubs: int;
            [<field: DataMember(Name = "delivered")>]
            Delivered: int;
            [<field: DataMember(Name = "emails_pct")>]
            EmailsPct: int;
            [<field: DataMember(Name = "bounces_pct")>]
            BouncesPct: int;
            [<field: DataMember(Name = "opens_pct")>]
            OpensPct: int;
            [<field: DataMember(Name = "clicks_pct")>]
            ClicksPct: int;
            [<field: DataMember(Name = "unsubs_pct")>]
            UnsubsPct: int }

    //------------------------------------------------------------------------------
    //  (*) Geo Opens
    //------------------------------------------------------------------------------

        [<DataContract(Namespace = "")>]
        type GeoOpens =
          { [<field: DataMember(Name = "code")>]
            Code: string;
            [<field: DataMember(Name = "name")>]
            Name: string;
            [<field: DataMember(Name = "opens")>]
            Opens: int;
            [<field: DataMember(Name = "region_detail")>]
            RegionDetail: bool mcnull }

    //------------------------------------------------------------------------------
    //  (*) Unsubscribes
    //------------------------------------------------------------------------------

        [<DataContract(Namespace = "")>]
        type UnsubscribesDataItem =
          { [<field: DataMember(Name = "email")>]
            Email: string;
            [<field: DataMember(Name = "reason")>]
            Reason: List.UnsubscribeReason mcnull;
            [<field: DataMember(Name = "reason_text")>]
            Description: string }

        [<DataContract(Namespace = "")>]
        type Unsubscribes =
          { [<field: DataMember(Name = "total")>]
            Total: int;
            [<field: DataMember(Name = "data")>]
            Data: MCList<UnsubscribesDataItem> }

//==================================================================================
//  Campaing report data section
//==================================================================================

    module ReportData =

    //------------------------------------------------------------------------------
    //  (*) Click Detail AIM
    //------------------------------------------------------------------------------

        [<DataContract(Namespace = "")>]
        type ClickDetail =
          { [<field: DataMember(Name = "email")>]
            Email: string;
            [<field: DataMember(Name = "clicks")>]
            Clicks: int }

        [<DataContract(Namespace = "")>]
        type ClickDetailAIM =
          { [<field: DataMember(Name = "total")>]
            Total: int;
            [<field: DataMember(Name = "data")>]
            Data: MCList<ClickDetail> }

    //------------------------------------------------------------------------------
    //  (*) Email Stats AIM
    //------------------------------------------------------------------------------

        [<DataContract(Namespace = "")>]
        type ActionType =
            | [<EnumMember(Value = "open")>] Open = 0
            | [<EnumMember(Value = "click")>] Click = 1

        [<DataContract(Namespace = "")>]
        type EmailAction =
          { [<field: DataMember(Name = "action")>]
            Action: ActionType;
            [<field: DataMember(Name = "timestamp")>]
            Timestamp: MCDateTime;
            [<field: DataMember(Name = "url")>]
            Url: string;
            [<field: DataMember(Name = "ip")>]
            IP: string }

        [<DataContract(Namespace = "")>]
        type EmailActivity =
          { [<field: DataMember(Name = "email_address")>]
            Email: string;
            [<field: DataMember(Name = "activity")>]
            Activity: MCList<EmailAction> }

        [<DataContract(Namespace = "")>]
        type EmailStatsAIM =
          { [<field: DataMember(Name = "success")>]
            Success: int;
            [<field: DataMember(Name = "error")>]
            Errors: int;
            [<field: DataMember(Name = "data")>]
            Data: MCList<EmailActivity>;
            ErrorsData: MCList<EmailError> }

        [<DataContract(Namespace = "")>]
        type EmailStatsAIMAll =
          { [<field: DataMember(Name = "total")>]
            Total: int;
            [<field: DataMember(Name = "data")>]
            Data: MCDict<string, MCList<EmailAction>> }

    //------------------------------------------------------------------------------
    //  (*) Opened/Not Opened AIM
    //------------------------------------------------------------------------------

        [<DataContract(Namespace = "")>]
        type OpensData =
          { [<field: DataMember(Name = "email")>]
            Email: string;
            [<field: DataMember(Name = "open_count")>]
            OpenCount: int }

        [<DataContract(Namespace = "")>]
        type OpenedAIM =
          { [<field: DataMember(Name = "total")>]
            Total: int;
            [<field: DataMember(Name = "data")>]
            Data: MCList<OpensData> }

        [<DataContract(Namespace = "")>]
        type NotOpenedAIM =
          { [<field: DataMember(Name = "total")>]
            Total: int;
            [<field: DataMember(Name = "data")>]
            Data: MCList<string> }

//==================================================================================
//  Folder related section
//==================================================================================

module Folder =

    [<DataContract(Namespace = "")>]
    type Type =
        | [<EnumMember(Value = "campaign")>] Campaign = 0
        | [<EnumMember(Value = "autoresponder")>] Autoresponder = 1

    [<DataContract(Namespace = "")>]
    type Folder =
      { [<field: DataMember(Name = "folder_id")>]
        FolderID: int;
        [<field: DataMember(Name = "name")>]
        Name: string;
        [<field: DataMember(Name = "date_created")>]
        DateCreated: MCDateTime;
        [<field: DataMember(Name = "type")>]
        Type: Type }

//==================================================================================
//  Template related section
//==================================================================================

module Template =

    //------------------------------------------------------------------------------
    //  (*) Templates
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type Type =
        | [<EnumMember(Value = "user")>] User = 0
        | [<EnumMember(Value = "gallery")>] Gallery = 1
        | [<EnumMember(Value = "base")>] Base = 2

    [<DataContract(Namespace = "")>]
    type Types() =
        [<DefaultValue; field: DataMember(Name = "user")>]
        val mutable User: bool
        [<DefaultValue; field: DataMember(Name = "gallery")>]
        val mutable Gallery: bool
        [<DefaultValue; field: DataMember(Name = "base")>]
        val mutable Base: bool

        interface IInput with
            member x.ToInput() = IH.build x

    [<DataContract(Namespace = "")>]
    type Inactives() =
        [<DefaultValue; field: DataMember(Name = "include")>]
        val mutable Include: bool
        [<DefaultValue; field: DataMember(Name = "only")>]
        val mutable Only: bool

        interface IInput with
            member x.ToInput() = IH.build x

    [<DataContract(Namespace = "")>]
    type Template =
      { [<field: DataMember(Name = "id")>]
        ID: int;
        [<field: DataMember(Name = "name")>]
        Name: string;
        [<field: DataMember(Name = "layout")>]
        Layout: string;
        [<field: DataMember(Name = "preview_image")>]
        PreviewImage: string;
        [<field: DataMember(Name = "date_created")>]
        DateCreated: MCDateTime;
        [<field: DataMember(Name = "active")>]
        Active: string;
        [<field: DataMember(Name = "edit_source")>]
        EditSource: string }

    [<DataContract(Namespace = "")>]
    type Templates =
      { [<field: DataMember(Name = "user")>]
        User: MCList<Template>;
        [<field: DataMember(Name = "gallery")>]
        Gallery: MCList<Template>;
        [<field: DataMember(Name = "base")>]
        Base: MCList<Template> }

    //------------------------------------------------------------------------------
    //  (*) Info
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type Info =
      { [<field: DataMember(Name = "default_content")>]
        DefaultContent: MCDict<string>;
        [<field: DataMember(Name = "sections")>]
        Sections: MCList<string>;
        [<field: DataMember(Name = "source")>]
        Source: string;
        [<field: DataMember(Name = "preview")>]
        Preview: string }

//==================================================================================
//  Ecommerce methods
//==================================================================================

module Ecommerce =

    //------------------------------------------------------------------------------
    //  (*) Orders
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type OrderDetails =
      { [<field: DataMember(Name = "line_num")>]
        LineNum: int;
        [<field: DataMember(Name = "product_id")>]
        ProductID: int;
        [<field: DataMember(Name = "product_name")>]
        ProductName: string;
        [<field: DataMember(Name = "product_sku")>]
        ProductSku: string;
        [<field: DataMember(Name = "product_category_id")>]
        CategoryID: int;
        [<field: DataMember(Name = "product_category_name")>]
        CategoryName: string;
        [<field: DataMember(Name = "qty")>]
        Quantity: int;
        [<field: DataMember(Name = "cost")>]
        Cost: float }

    [<DataContract(Namespace = "")>]
    type OrdersDataItem =
      { [<field: DataMember(Name = "store_id")>]
        StoreID: string;
        [<field: DataMember(Name = "store_name")>]
        StoreName: string;
        [<field: DataMember(Name = "order_id")>]
        OrderID: string;
        [<field: DataMember(Name = "campaign_id")>]
        CampaignID: string;
        [<field: DataMember(Name = "email")>]
        Email: string;
        [<field: DataMember(Name = "order_total")>]
        OrderTotal: float;
        [<field: DataMember(Name = "tax_total")>]
        TaxTotal: float mcnull;
        [<field: DataMember(Name = "ship_total")>]
        ShipTotal: float mcnull;
        [<field: DataMember(Name = "order_date")>]
        OrderDate: MCDateTime;
        [<field: DataMember(Name = "lines")>]
        Lines: MCList<OrderDetails> }

    [<DataContract(Namespace = "")>]
    type Orders =
      { [<field: DataMember(Name = "total")>]
        Total: int;
        [<field: DataMember(Name = "data")>]
        Data: MCList<OrdersDataItem> }

    //------------------------------------------------------------------------------
    //  (*) Add
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type OrderItem() =
        [<DefaultValue; field: DataMember(Name = "line_num")>]
        val mutable LineNum: int opt
        [<DefaultValue; field: DataMember(Name = "product_id")>]
        val mutable ProductID: int
        [<DefaultValue; field: DataMember(Name = "product_name")>]
        val mutable ProductName: string
        [<DefaultValue; field: DataMember(Name = "category_id")>]
        val mutable CategoryID: int
        [<DefaultValue; field: DataMember(Name = "category_name")>]
        val mutable CategoryName: string
        [<DefaultValue; field: DataMember(Name = "sku")>]
        val mutable Sku: string
        [<DefaultValue; field: DataMember(Name = "qty")>]
        val mutable Quantity: float
        [<DefaultValue; field: DataMember(Name = "cost")>]
        val mutable Cost: float

        interface IInput with
            member x.ToInput() = IH.build x

    [<DataContract(Namespace = "")>]
    type Order() =
        [<DefaultValue; field: DataMember(Name = "id")>]
        val mutable ID: string
        [<DefaultValue; field: DataMember(Name = "email_id")>]
        val mutable EmailID: string
        [<DefaultValue; field: DataMember(Name = "email")>]
        val mutable Email: string
        [<DefaultValue; field: DataMember(Name = "total")>]
        val mutable Total: float
        [<DefaultValue; field: DataMember(Name = "order_date")>]
        val mutable OrderDate: DateTime opt
        [<DefaultValue; field: DataMember(Name = "shipping")>]
        val mutable Shipping: float opt
        [<DefaultValue; field: DataMember(Name = "tax")>]
        val mutable Tax: float opt
        [<DefaultValue; field: DataMember(Name = "store_id")>]
        val mutable StoreID: string
        [<DefaultValue; field: DataMember(Name = "store_name")>]
        val mutable StoreName: string
        [<DefaultValue; field: DataMember(Name = "plugin_id")>]
        val mutable PluginID: string
        [<DefaultValue; field: DataMember(Name = "campaign_id")>]
        val mutable CampaignID: string
        [<DefaultValue; field: DataMember(Name = "items")>]
        val mutable Items: OrderItem[]

        interface IInput with
            member x.ToInput() = IH.build x

//==================================================================================
//  Helper section
//==================================================================================

module Helper =

    //------------------------------------------------------------------------------
    //  (*) Account Details
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type PlanType =
        | [<EnumMember(Value = "free")>] Free = 0
        | [<EnumMember(Value = "monthly")>] Monthly = 1
        | [<EnumMember(Value = "payasyougo")>] PayAsYouGo = 2

    [<DataContract(Namespace = "")>]
    type OrderType =
        | [<EnumMember(Value = "monthly")>] Monthly = 0
        | [<EnumMember(Value = "credits")>] Credits = 1

    [<DataContract(Namespace = "")>]
    type DetailType =
        | [<EnumMember(Value = "modules")>] Modules = 0
        | [<EnumMember(Value = "orders")>] Orders = 1
        | [<EnumMember(Value = "rewards-credits")>] RewardsCredits = 2
        | [<EnumMember(Value = "rewards-inspections")>] RewardsInspections = 3
        | [<EnumMember(Value = "rewards-referrals")>] RewardsReferrals = 4
        | [<EnumMember(Value = "rewards-applied")>] RewardsApplied = 5

    [<DataContract(Namespace = "")>]
    type Contact =
      { [<field: DataMember(Name = "fname")>]
        FirstName: string;
        [<field: DataMember(Name = "lname")>]
        LastName: string;
        [<field: DataMember(Name = "email")>]
        Email: string;
        [<field: DataMember(Name = "company")>]
        Company: string;
        [<field: DataMember(Name = "address1")>]
        Address1: string;
        [<field: DataMember(Name = "address2")>]
        Address2: string;
        [<field: DataMember(Name = "city")>]
        City: string;
        [<field: DataMember(Name = "state")>]
        State: string;
        [<field: DataMember(Name = "zip")>]
        Zip: string;
        [<field: DataMember(Name = "country")>]
        Country: string;
        [<field: DataMember(Name = "url")>]
        Url: string;
        [<field: DataMember(Name = "phone")>]
        Phone: string;
        [<field: DataMember(Name = "fax")>]
        Fax: string }

    [<DataContract(Namespace = "")>]
    type Module =
      { [<field: DataMember(Name = "id")>]
        ID: int;
        [<field: DataMember(Name = "name")>]
        Name: string;
        [<field: DataMember(Name = "added")>]
        Added: MCDateTime;
        [<field: DataMember(Name = "data")>]
        Data: MCDict<string> }

    [<DataContract(Namespace = "")>]
    type Order =
      { [<field: DataMember(Name = "order_id")>]
        OrderID: int;
        [<field: DataMember(Name = "type")>]
        Type: OrderType;
        [<field: DataMember(Name = "amount")>]
        Amount: float;
        [<field: DataMember(Name = "date")>]
        Date: MCDateTime;
        [<field: DataMember(Name = "credits_used")>]
        CreditsUsed: float }

    [<DataContract(Namespace = "")>]
    type Earnings =
      { [<field: DataMember(Name = "this_month")>]
        ThisMonth: float;
        [<field: DataMember(Name = "total_earned")>]
        TotalEarned: float;
        [<field: DataMember(Name = "remaining")>]
        Remaining: float }

    [<DataContract(Namespace = "")>]
    type Referral =
      { [<field: DataMember(Name = "name")>]
        Name: string;
        [<field: DataMember(Name = "email")>]
        Email: string;
        [<field: DataMember(Name = "signup_date")>]
        SignupDate: MCDateTime;
        [<field: DataMember(Name = "type")>]
        Type: string }

    [<DataContract(Namespace = "")>]
    type AppliedReward =
      { [<field: DataMember(Name = "value")>]
        Value: int;
        [<field: DataMember(Name = "date")>]
        Date: MCDateTime;
        [<field: DataMember(Name = "order_id")>]
        OrderID: int;
        [<field: DataMember(Name = "order_desc")>]
        OrderDesc: string }

    [<DataContract(Namespace = "")>]
    type Rewards =
      { [<field: DataMember(Name = "referrals_this_month")>]
        ReferralsThisMonth: int;
        [<field: DataMember(Name = "notify_on")>]
        NotifyOn: MCBool;
        [<field: DataMember(Name = "notify_email")>]
        NotifyEmail: string;
        [<field: DataMember(Name = "credits")>]
        Credits: Earnings;
        [<field: DataMember(Name = "inspections")>]
        Inspections: Earnings;
        [<field: DataMember(Name = "referrals")>]
        Referrals: MCList<Referral>;
        [<field: DataMember(Name = "applied")>]
        Applied: MCList<AppliedReward> }

    [<DataContract(Namespace = "")>]
    type AccountDetails =
      { [<field: DataMember(Name = "user_id")>]
        UserID: string;
        [<field: DataMember(Name = "username")>]
        Username: string;
        [<field: DataMember(Name = "member_since")>]
        MemberSince: MCDateTime;
        [<field: DataMember(Name = "is_approved")>]
        IsApproved: MCBool;
        [<field: DataMember(Name = "is_trial")>]
        IsTrial: MCBool;
        [<field: DataMember(Name = "has_activated")>]
        HasActivated: MCBool;
        [<field: DataMember(Name = "timezone")>]
        Timezone: string;
        [<field: DataMember(Name = "plan_type")>]
        PlanType: PlanType;
        [<field: DataMember(Name = "plan_low")>]
        PlanLow: int;
        [<field: DataMember(Name = "plan_high")>]
        PlanHigh: int;
        [<field: DataMember(Name = "plan_start_date")>]
        PlanStartDate: MCDateTime;
        [<field: DataMember(Name = "emails_left")>]
        EmailsLeft: int;
        [<field: DataMember(Name = "pending_monthly")>]
        PendingMonthly: MCBool;
        [<field: DataMember(Name = "first_payment")>]
        FirstPayment: MCDateTime;
        [<field: DataMember(Name = "last_payment")>]
        LastPayment: MCDateTime;
        [<field: DataMember(Name = "times_logged_in")>]
        TimesLoggedIn: int;
        [<field: DataMember(Name = "last_login")>]
        LastLogin: MCDateTime;
        [<field: DataMember(Name = "affiliate_link")>]
        AffiliateLink: string;
        [<field: DataMember(Name = "contact")>]
        Contact: Contact;
        [<field: DataMember(Name = "modules")>]
        Modules: MCList<Module>;
        [<field: DataMember(Name = "orders")>]
        Orders: MCList<Order>;
        [<field: DataMember(Name = "rewards")>]
        Rewards: Rewards }

    //------------------------------------------------------------------------------
    //  (*) Domains
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type DomainStatus =
        | [<EnumMember(Value = "verified")>] Verified = 0
        | [<EnumMember(Value = "pending")>] Pending = 1

    [<DataContract(Namespace = "")>]
    type Domain =
      { [<field: DataMember(Name = "domain")>]
        Domain: string;
        [<field: DataMember(Name = "status")>]
        Status: DomainStatus;
        [<field: DataMember(Name = "email")>]
        Email: string }

    //------------------------------------------------------------------------------
    //  (*) ChimpChatter
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type ChimpChatterItem =
      { [<field: DataMember(Name = "message")>]
        Message: string;
        [<field: DataMember(Name = "type")>]
        Type: string;
        [<field: DataMember(Name = "url")>]
        Url: string;
        [<field: DataMember(Name = "list_id")>]
        ListID: string;
        [<field: DataMember(Name = "campaign_id")>]
        CampaignID: string;
        [<field:DataMember(Name = "update_time")>]
        UpdateTime: MCDateTime }

    //------------------------------------------------------------------------------
    //  (*) Search Members
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type MembersMatches =
      { [<field: DataMember(Name = "total")>]
        Total: int;
        [<field: DataMember(Name = "members")>]
        Members: MCList<List.MemberInfoDataItem> }

    [<DataContract(Namespace = "")>]
    type SearchMembersResult =
      { [<field: DataMember(Name = "exact_matches")>]
        ExactMatches: MembersMatches;
        [<field: DataMember(Name = "full_search")>]
        FullSearch: MembersMatches }

    //------------------------------------------------------------------------------
    //  (*) Search Campaigns
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type CampaignsMatch =
      { [<field: DataMember(Name = "snippet")>]
        Snippet: string;
        [<field: DataMember(Name = "campaign")>]
        Campaign: Campaign.CampaignsDataItem }

    [<DataContract(Namespace = "")>]
    type SearchCampaignsResult =
      { [<field: DataMember(Name = "total")>]
        Total: int;
        [<field: DataMember(Name = "results")>]
        Results: MCList<CampaignsMatch> }

//==================================================================================
//  Golden Monkeys
//==================================================================================

module GoldenMonkeys =

    [<DataContract(Namespace = "")>]
    type Member =
      { [<field: DataMember(Name = "list_id")>]
        ListID: string;
        [<field: DataMember(Name = "list_name")>]
        ListName: string;
        [<field: DataMember(Name = "email")>]
        Email: string;
        [<field: DataMember(Name = "fname")>]
        FirstName: string;
        [<field: DataMember(Name = "lname")>]
        LastName: string;
        [<field: DataMember(Name = "member_rating")>]
        MemberRating: int;
        [<field: DataMember(Name = "member_since")>]
        MemberSince: MCDateTime }

    [<DataContract(Namespace = "")>]
    type MemberOpResult =
      { [<field: DataMember(Name = "success")>]
        Success: int;
        [<field: DataMember(Name = "errors")>]
        Errors: int;
        [<field: DataMember(Name = "data")>]
        ErrorsData: MCList<EmailError> }

    [<DataContract(Namespace = "")>]
    type MemberAction =
      { [<field: DataMember(Name = "action")>]
        Action: List.MemberActionType;
        [<field: DataMember(Name = "timestamp")>]
        Timestamp: MCDateTime;
        [<field: DataMember(Name = "url")>]
        Url: string;
        [<field: DataMember(Name = "unique_id")>]
        UniqueID: string;
        [<field: DataMember(Name = "title")>]
        Title: string;
        [<field: DataMember(Name = "list_name")>]
        ListName: string;
        [<field: DataMember(Name = "email")>]
        Email: string;
        [<field: DataMember(Name = "fname")>]
        FirstName: string;
        [<field: DataMember(Name = "lname")>]
        LastName: string;
        [<field: DataMember(Name = "member_rating")>]
        MemberRating: int;
        [<field: DataMember(Name = "member_since")>]
        MemberSince: MCDateTime;
        [<field: DataMember(Name = "geo")>]
        Geo: List.Geo }

//==================================================================================
//  Export API
//==================================================================================

module Export =

    //------------------------------------------------------------------------------
    //  (*) List
    //------------------------------------------------------------------------------

    type ListData =
      { Header: string[];
        Data: obj[][] }

    //------------------------------------------------------------------------------
    //  (*) Subscriber activity
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type SubsriberAction =
      { [<field: DataMember(Name = "action")>]
        Action: string;
        [<field: DataMember(Name = "timestamp")>]
        Timestamp: string;
        [<field: DataMember(Name = "url")>]
        Url: string;
        [<field: DataMember(Name = "ip")>]
        IP: string }

    //------------------------------------------------------------------------------
    //  (*) Ecommerce
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type EcommOrder =
      { [<field: DataMember(Name = "store_id")>]
        StoreID: string;
        [<field: DataMember(Name = "store_name")>]
        StoreName: string;
        [<field: DataMember(Name = "order_id")>]
        OrderID: string;
        [<field: DataMember(Name = "campaign_id")>]
        CampaignID: string;
        [<field: DataMember(Name = "email")>]
        Email: string;
        [<field: DataMember(Name = "order_total")>]
        OrderTotal: float;
        [<field: DataMember(Name = "tax_total")>]
        TaxTotal: float;
        [<field: DataMember(Name = "ship_total")>]
        ShipTotal: float;
        [<field: DataMember(Name = "order_date")>]
        OrderDate: string;
        [<field: DataMember(Name = "lines")>]
        Lines: Ecommerce.OrderDetails[] }

//==================================================================================
//  Mandrill API
//==================================================================================

module Mandrill =

    open System.Collections.Generic

    [<DataContract(Namespace = "")>]
    type Error() =
        inherit MailChimp.Types.Error()
        [<field: DataMember(Name = "code")>]
        let code: int = 0
        [<field: DataMember(Name = "name")>]
        let name: string = null
        [<field: DataMember(Name = "message")>]
        let msg: string = null

        member x.Name = name
        override x.Code = code
        override x.Message = msg

    /// Defines a generic name/content pair.
    type NameContentPair<'a> =
      { [<field: DataMember(Name = "name")>]
        Name: string;
        [<field: DataMember(Name = "content")>]
        Content: 'a }

        static member Create(name, content) =
          { Name = name; Content = content }

        interface IInput with
            member x.ToInput() = IH.build x

    /// Represents a collection of name-content pairs.
    type NameContentList<'a>() =
        inherit ResizeArray<NameContentPair<'a>>()

        member x.Add(name, content) =
            x.Add({ Name = name; Content = content })

    //------------------------------------------------------------------------------
    //  (*) Stats/Info
    //------------------------------------------------------------------------------

    [<DataContract(Namespace = "")>]
    type Stats =
      { [<field: DataMember(Name = "time")>]
        Time: MCDateTime mcnull;
        [<field: DataMember(Name = "sent")>]
        Sent: int;
        [<field: DataMember(Name = "hard_bounces")>]
        HardBounces: int;
        [<field: DataMember(Name = "soft_bounces")>]
        SoftBounces: int;
        [<field: DataMember(Name = "rejects")>]
        Rejects: int;
        [<field: DataMember(Name = "complaints")>]
        Complaints: int;
        [<field: DataMember(Name = "unsubs")>]
        Unsubs: int;
        [<field: DataMember(Name = "opens")>]
        Opens: int;
        [<field: DataMember(Name = "unique_opens")>]
        UniqueOpens: int;
        [<field: DataMember(Name = "clicks")>]
        Clicks: int;
        [<field: DataMember(Name = "unique_clicks")>]
        UniqueClicks: int }

    [<DataContract(Namespace = "")>]
    type PeriodStats =
      { [<field: DataMember(Name = "today")>]
        Today: Stats;
        [<field: DataMember(Name = "last_7_days")>]
        Last7Days: Stats;
        [<field: DataMember(Name = "last_30_days")>]
        Last30Days: Stats;
        [<field: DataMember(Name = "last_60_days")>]
        Last60Days: Stats;
        [<field: DataMember(Name = "last_90_days")>]
        Last90Days: Stats;
        [<field: DataMember(Name = "all_time")>]
        AllTime: Stats }

    [<DataContract(Namespace = "")>]
    type UserInfo =
      { [<field: DataMember(Name = "username")>]
        Username: string;
        [<field: DataMember(Name = "created_at")>]
        CreatedAt: MCDateTime;
        [<field: DataMember(Name = "public_id")>]
        PublicID: string;
        [<field: DataMember(Name = "reputation")>]
        Reputation: int;
        [<field: DataMember(Name = "hourly_quota")>]
        HourlyQuota: int;
        [<field: DataMember(Name = "backlog")>]
        BackLog: int;
        [<field: DataMember(Name = "stats")>]
        Stats: PeriodStats }

    [<DataContract(Namespace = "")>]
    type TagInfo =
      { [<field: DataMember(Name = "tag")>]
        Tag: string;
        [<field: DataMember(Name = "sent")>]
        Sent: int;
        [<field: DataMember(Name = "hard_bounces")>]
        HardBounces: int;
        [<field: DataMember(Name = "soft_bounces")>]
        SoftBounces: int;
        [<field: DataMember(Name = "rejects")>]
        Rejects: int;
        [<field: DataMember(Name = "complaints")>]
        Complaints: int;
        [<field: DataMember(Name = "unsubs")>]
        Unsubs: int;
        [<field: DataMember(Name = "opens")>]
        Opens: int;
        [<field: DataMember(Name = "clicks")>]
        Clicks: int;
        [<field: DataMember(Name = "stats")>]
        Stats: PeriodStats }

    [<DataContract(Namespace = "")>]
    type SenderInfo =
      { [<field: DataMember(Name = "address")>]
        Address: string;
        [<field: DataMember(Name = "created_at")>]
        CreatedAt: MCDateTime;
        [<field: DataMember(Name = "sent")>]
        Sent: int;
        [<field: DataMember(Name = "hard_bounces")>]
        HardBounces: int;
        [<field: DataMember(Name = "soft_bounces")>]
        SoftBounces: int;
        [<field: DataMember(Name = "rejects")>]
        Rejects: int;
        [<field: DataMember(Name = "complaints")>]
        Complaints: int;
        [<field: DataMember(Name = "unsubs")>]
        Unsubs: int;
        [<field: DataMember(Name = "opens")>]
        Opens: int;
        [<field: DataMember(Name = "clicks")>]
        Clicks: int;
        [<field: DataMember(Name = "stats")>]
        Stats: PeriodStats }

    [<DataContract(Namespace = "")>]
    type Domain =
      { [<field: DataMember(Name = "domain")>]
        Domain: string;
        [<field: DataMember(Name = "created_at")>]
        CreatedAt: MCDateTime mcnull;
        [<field: DataMember(Name = "valid_mx")>]
        ValidMX: bool mcnull }

    [<DataContract(Namespace = "")>]
    type UrlInfo =
      { [<field: DataMember(Name = "url")>]
        Url: string;
        [<field: DataMember(Name = "sent")>]
        Sent: int;
        [<field: DataMember(Name = "clicks")>]
        Clicks: int;
        [<field: DataMember(Name = "unique_clicks")>]
        UniqueClicks: int }

    [<DataContract(Namespace = "")>]
    type UrlStats =
      { [<field: DataMember(Name = "time")>]
        Time: MCDateTime;
        [<field: DataMember(Name = "user_tag")>]
        UserTag: string;
        [<field: DataMember(Name = "sent")>]
        Sent: int;
        [<field: DataMember(Name = "clicks")>]
        Clicks: int;
        [<field: DataMember(Name = "unique_clicks")>]
        UniqueClicks: int }

    [<DataContract(Namespace = "")>]
    type TemplateInfo =
      { [<field: DataMember(Name = "slug")>]
        Slug: string;
        [<field: DataMember(Name = "name")>]
        Name: string;
        [<field: DataMember(Name = "code")>]
        Code: string;
        [<field: DataMember(Name = "subject")>]
        Subject: string;
        [<field: DataMember(Name = "from_email")>]
        FromEmail: string;
        [<field: DataMember(Name = "from_name")>]
        FromName: string;
        [<field: DataMember(Name = "text")>]
        Text: string;
        [<field: DataMember(Name = "publish_name")>]
        PublishName: string;
        [<field: DataMember(Name = "publish_code")>]
        PublishCode: string;
        [<field: DataMember(Name = "publish_subject")>]
        PublishSubject: string;
        [<field: DataMember(Name = "publish_from_email")>]
        PublishFromEmail: string;
        [<field: DataMember(Name = "publish_from_name")>]
        PublishFromName: string;
        [<field: DataMember(Name = "publish_text")>]
        PublishText: string;
        [<field: DataMember(Name = "published_at")>]
        PublishedAt: MCDateTime mcnull;
        [<field: DataMember(Name = "created_at")>]
        CreatedAt: MCDateTime;
        [<field: DataMember(Name = "updated_at")>]
        UpdatedAt: MCDateTime }

    [<DataContract(Namespace = "")>]
    type internal RenderResult =
      { [<field: DataMember(Name = "html")>]
        Html: string }

    [<DataContract(Namespace = "")>]
    type EventType =
        | [<EnumMember(Value = "send")>] Send = 0
        | [<EnumMember(Value = "hard_bounce")>] HardBounce = 1
        | [<EnumMember(Value = "soft_bounce")>] SoftBounce = 2
        | [<EnumMember(Value = "open")>] Open = 3
        | [<EnumMember(Value = "click")>] Click = 4
        | [<EnumMember(Value = "spam")>] Spam = 5
        | [<EnumMember(Value = "unsub")>] Unsub = 6
        | [<EnumMember(Value = "reject")>] Reject = 7

    [<DataContract(Namespace = "")>]
    type WebhookInfo =
      { [<field: DataMember(Name = "id")>]
        ID: int;
        [<field: DataMember(Name = "url")>]
        Url: string;
        [<field: DataMember(Name = "description")>]
        Description: string;
        [<field: DataMember(Name = "auth_key")>]
        AuthKey: string;
        [<field: DataMember(Name = "events")>]
        Events: MVList<EventType>;
        [<field: DataMember(Name = "created_at")>]
        CreatedAt: MCDateTime;
        [<field: DataMember(Name = "last_sent_at")>]
        LastSentAt: MCDateTime mcnull;
        [<field: DataMember(Name = "batches_sent")>]
        BatchesSent: int;
        [<field: DataMember(Name = "events_sent")>]
        EventsSent: int;
        [<field: DataMember(Name = "last_error")>]
        LastError: string }

    //------------------------------------------------------------------------------
    //  (*) Rejections black/whitelist
    //------------------------------------------------------------------------------

    module Rejections =

        [<DataContract(Namespace = "")>]
        type RejectReason =
            | [<EnumMember(Value = "hard-bounce")>] HardBounce = 0
            | [<EnumMember(Value = "soft-bounce")>] SoftBounce = 1
            | [<EnumMember(Value = "spam")>] Spam = 2
            | [<EnumMember(Value = "unsub")>] Unsub = 3
            | [<EnumMember(Value = "custom")>] Custom = 4

        [<DataContract(Namespace = "")>]
        type BlacklistItem =
          { [<field: DataMember(Name = "email")>]
            Email: string;
            [<field: DataMember(Name = "reason")>]
            Reason: RejectReason;
            [<field: DataMember(Name = "detail")>]
            Detail: string;
            [<field: DataMember(Name = "created_at")>]
            CreatedAt: MCDateTime;
            [<field: DataMember(Name = "last_event_at")>]
            LastEventAt: MCDateTime;
            [<field: DataMember(Name = "expires_at")>]
            ExpiresAt: MCDateTime;
            [<field: DataMember(Name = "expired")>]
            Expired: bool;
            [<field: DataMember(Name = "sender")>]
            Sender: SenderInfo }

        [<DataContract(Namespace = "")>]
        type WhitelistItem =
          { [<field: DataMember(Name = "email")>]
            Email: string;
            [<field: DataMember(Name = "detail")>]
            Detail: string;
            [<field: DataMember(Name = "created_at")>]
            CreatedAt: MCDateTime }

        [<DataContract(Namespace = "")>]
        type internal ListAddResult =
          { [<field: DataMember(Name = "email")>]
            Email: string;
            [<field: DataMember(Name = "added")>]
            Added: bool }

        [<DataContract(Namespace = "")>]
        type internal ListDelResult =
          { [<field: DataMember(Name = "email")>]
            Email: string;
            [<field: DataMember(Name = "deleted")>]
            Deleted: bool }

    //------------------------------------------------------------------------------
    //  (*) Messages
    //------------------------------------------------------------------------------

    module Messages =

        [<DataContract(Namespace = "")>]
        type Recipient =
          { [<field: DataMember(Name = "email")>]
            Email: string;
            [<field: DataMember(Name = "name")>]
            Name: string }

            interface IInput with
                member x.ToInput() = IH.build x

        [<DataContract(Namespace = "")>]
        type MergeVars =
          { [<field: DataMember(Name = "rcpt")>]
            Recipient: string;
            [<field: DataMember(Name = "vars")>]
            Merges: NameContentList<string> }

            static member Create(recipient, merges) =
              { Recipient = recipient; Merges = merges }

            interface IInput with
                member x.ToInput() = IH.build x

        [<DataContract(Namespace = "")>]
        type Metadata =
          { [<field: DataMember(Name = "rcpt")>]
            Recipient: string;
            [<field: DataMember(Name = "values")>]
            Values: MCDict<string> }

            static member Create(recipient, values) =
              { Recipient = recipient; Values = values }

            interface IInput with
                member x.ToInput() = IH.build x

        [<DataContract(Namespace = "")>]
        type Attachment =
          { [<field: DataMember(Name = "type")>]
            Type: string;
            [<field: DataMember(Name = "name")>]
            Name: string;
            [<field: DataMember(Name = "binary")>]
            Binary: bool mcnull;
            [<field: DataMember(Name = "content")>]
            Content: string }

            member x.ToBinary() =
                if x.Binary.Equals(false) then
                    let c = getBytesUTF8 (x.Content @? "")
                    Attachment.Create(x.Type, x.Name, c)
                else x

            static member Create(typ, name, content: byte[]) =
              { Type = typ; Name = name; Binary = MCNull<bool>();
                Content = Convert.ToBase64String(content) }

            interface IInput with
                member x.ToInput() = IH.build x

        type Header private (value) =
            inherit VarList<string, MVList<string>>(value)

            private new() = Header(Null)

            static member op_Implicit(x) = Header(Sn x)
            static member op_Implicit(x) = Header(Sq x)

            static member Create(x) = Header(Sn x)
            static member Create(x) = Header(Sq x)

            interface IValue with
                member x.Value =
                    match x.Value with
                    | Sn v -> box v | Sq v -> box v | _ -> null

        [<DataContract(Namespace = "")>]
        type Message() =
            [<DefaultValue; field: DataMember(Name = "html")>]
            val mutable Html: string
            [<DefaultValue; field: DataMember(Name = "text")>]
            val mutable Text: string
            [<DefaultValue; field: DataMember(Name = "subject")>]
            val mutable Subject: string
            [<DefaultValue; field: DataMember(Name = "from_email")>]
            val mutable FromEmail: string
            [<DefaultValue; field: DataMember(Name = "from_name")>]
            val mutable FromName: string
            [<DefaultValue; field: DataMember(Name = "to")>]
            val mutable To: Recipient[]
            [<DefaultValue; field: DataMember(Name = "headers")>]
            val mutable Headers: MCDict<Header> opt
            [<DefaultValue; field: DataMember(Name = "important")>]
            val mutable Important: bool opt
            [<DefaultValue; field: DataMember(Name = "track_opens")>]
            val mutable TrackOpens: bool opt
            [<DefaultValue; field: DataMember(Name = "track_clicks")>]
            val mutable TrackClicks: bool opt
            [<DefaultValue; field: DataMember(Name = "auto_text")>]
            val mutable AutoText: bool opt
            [<DefaultValue; field: DataMember(Name = "auto_html")>]
            val mutable AutoHtml: bool opt
            [<DefaultValue; field: DataMember(Name = "inline_css")>]
            val mutable InlineCss: bool opt
            [<DefaultValue; field: DataMember(Name = "url_strip_qs")>]
            val mutable UrlStripQueryString: bool opt
            [<DefaultValue; field: DataMember(Name = "preserve_recipients")>]
            val mutable PreserveRecipients: bool opt
            [<DefaultValue; field: DataMember(Name = "bcc_address")>]
            val mutable BccAddress: string
            [<DefaultValue; field: DataMember(Name = "tracking_domain")>]
            val mutable TrackingDomain: string
            [<DefaultValue; field: DataMember(Name = "signing_domain")>]
            val mutable SigningDomain: string
            [<DefaultValue; field: DataMember(Name = "merge")>]
            val mutable Merge: bool opt
            [<DefaultValue; field: DataMember(Name = "global_merge_vars")>]
            val mutable GlobalMergeVars: NameContentList<string> opt
            [<DefaultValue; field: DataMember(Name = "merge_vars")>]
            val mutable MergeVars: MergeVars[] opt
            [<DefaultValue; field: DataMember(Name = "tags")>]
            val mutable Tags: string[] opt
            [<DefaultValue; field: DataMember(Name = "google_analytics_domains")>]
            val mutable GoogleAnalyticsDomains: string[] opt
            [<DefaultValue; field: DataMember(Name = "google_analytics_campaign")>]
            val mutable GoogleAnalyticsCampaign: string
            [<DefaultValue; field: DataMember(Name = "metadata")>]
            val mutable Metadata: MCDict<string> opt
            [<DefaultValue; field: DataMember(Name = "recipient_metadata")>]
            val mutable RecipientMetadata: Metadata[] opt
            [<DefaultValue; field: DataMember(Name = "attachments")>]
            val mutable Attachments: Attachment[] opt
            [<DefaultValue; field: DataMember(Name = "images")>]
            val mutable Images: Attachment[] opt

            interface IInput with
                member x.ToInput() = IH.build x

        [<DataContract(Namespace = "")>]
        type ParsedMessage =
          { [<DefaultValue; field: DataMember(Name = "subject")>]
            Subject: string;
            [<DefaultValue; field: DataMember(Name = "from_email")>]
            FromEmail: string;
            [<DefaultValue; field: DataMember(Name = "from_name")>]
            FromName: string;
            [<DefaultValue; field: DataMember(Name = "to")>]
            To: MVList<Recipient>;
            [<DefaultValue; field: DataMember(Name = "headers")>]
            Headers: MCDict<Header>;
            [<DefaultValue; field: DataMember(Name = "html")>]
            Html: string;
            [<DefaultValue; field: DataMember(Name = "text")>]
            Text: string;
            [<DefaultValue; field: DataMember(Name = "attachments")>]
            Attachments: MCDict<Attachment>;
            [<DefaultValue; field: DataMember(Name = "images")>]
            Images: MCDict<Attachment> }

            /// <summary>Converts to 'Message' object that can be send using 'Send' method.</summary>
            /// <remarks>C# specific optional parameters.</remarks>
            /// <param name="headerFilter">[optional] Regex for headers filtering.
            /// <para>Defaults to "Reply-To|X-.+".</para></param>
            member x.ToMessage([<op>]headerFilter: string opt) =
                let msg = Message()
                msg.Subject <- x.Subject
                msg.FromEmail <- x.FromEmail
                msg.FromName <- x.FromName
                msg.Html <- x.Html
                msg.Text <- x.Text

                let getAttachments (a: MCDict<Attachment>) =
                    a |> Seq.map (fun kv -> kv.Value.ToBinary()) |> Seq.toArray |> Some

                if x.To != null then
                    msg.To <- x.To |> Seq.toArray

                if x.Attachments != null then
                    msg.Attachments <- x.Attachments |> getAttachments

                if x.Images != null then
                    msg.Images <- x.Images |> getAttachments

                if x.Headers != null then
                    let filter = defValue headerFilter @"Reply-To|X-.+"
                    let d, rgx = MCDict<Header>(), regex filter
                    x.Headers |> Seq.iter(fun z ->
                        if rgx.IsMatch(z.Key) then d.Add(z.Key, z.Value))
                    msg.Headers <- Some d
                msg

            /// <summary>Converts to 'Message' object that can be send using 'Send' method.</summary>
            /// <remarks>F# specific optional parameters.</remarks>
            /// <param name="headerFilter">[optional] Regex for headers filtering.
            /// <para>Defaults to "Reply-To|X-.+".</para></param>
            member x.ToMessage(?headerFilter: string) = x.ToMessage((<?)headerFilter)

        [<DataContract(Namespace = "")>]
        type Status =
            | [<EnumMember(Value = "sent")>] Sent = 0
            | [<EnumMember(Value = "queued")>] Queued = 1
            | [<EnumMember(Value = "bounced")>] Bounced = 2
            | [<EnumMember(Value = "soft-bounced")>] SoftBounced = 3
            | [<EnumMember(Value = "rejected")>] Rejected = 4
            | [<EnumMember(Value = "invalid")>] Invalid = 5

        [<DataContract(Namespace = "")>]
        type SendResult =
          { [<field: DataMember(Name = "_id")>]
            ID: string;
            [<field: DataMember(Name = "email")>]
            Email: string;
            [<field: DataMember(Name = "status")>]
            Status: Status }

        [<DataContract(Namespace = "")>]
        type SearchResult =
          { [<field: DataMember(Name = "_id")>]
            ID: string;
            [<field: DataMember(Name = "ts")>]
            Timestamp : int;
            [<field: DataMember(Name = "sender")>]
            Sender : string;
            [<field: DataMember(Name = "subject")>]
            Subject : string;
            [<field: DataMember(Name = "email")>]
            Email : string;
            [<field: DataMember(Name = "tags")>]
            Tags : MVList<string>;
            [<field: DataMember(Name = "opens")>]
            Opens : int;
            [<field: DataMember(Name = "clicks")>]
            Clicks : int;
            [<field: DataMember(Name = "state")>]
            State : Status;
            [<field: DataMember(Name = "metadata")>]
            Metadata: MCDict<string> }

    //------------------------------------------------------------------------------
    //  (*) Inbound
    //------------------------------------------------------------------------------

    module Inbound =

        [<DataContract(Namespace = "")>]
        type Route =
          { [<field: DataMember(Name = "pattern")>]
            Pattern: string;
            [<field: DataMember(Name = "url")>]
            Url: string }

        [<DataContract(Namespace = "")>]
        type Recipient =
          { [<field: DataMember(Name = "email")>]
            Email: string;
            [<field: DataMember(Name = "pattern")>]
            Pattern: string;
            [<field: DataMember(Name = "url")>]
            Url: string }